diff --git a/.gitignore b/.gitignore index da9b4041..afd34aaa 100755 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ composer.phar /app/config/local /app/config/staging /app/config/production +/app/config/packages /bootstrap/compiled.php /installed/* !/installed/.gitkeep diff --git a/.travis.yml b/.travis.yml index f98429a0..09466701 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,12 +2,14 @@ language: php services: mysql php: - "5.4" + - "5.6" env: - DB=mysql before_script: - mysql -e 'CREATE DATABASE core_test;' - sudo hostname test.travis-ci.org - pecl install dbase + - echo "extension = dbase.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - composer install script: diff --git a/app/Tdt/Core/Analytics/GaTracker.php b/app/Tdt/Core/Analytics/GaTracker.php new file mode 100644 index 00000000..3dcd9e36 --- /dev/null +++ b/app/Tdt/Core/Analytics/GaTracker.php @@ -0,0 +1,94 @@ + + * @author appreciate.be + */ + +class GaTracker implements TrackerInterface +{ + private $IGNORE = ['api', 'discovery']; + + public function track($request, $tracker_id) + { + $path = $request->path(); + $extension = ''; + + if (strpos($path, '.') !== false) { + $uri_parts = explode('.', $request->path()); + + $extension = strtolower(array_pop($uri_parts)); + $path = implode('', $uri_parts); + } else { + $extension = 'html'; + } + + // Get some meta-data from the definition to add to the GA as a dimension + $definitions = \App::make('Tdt\Core\Repositories\Interfaces\DefinitionRepositoryInterface'); + $definition = $definitions->getByIdentifier($path); + + $license = 'Not provided'; + $theme = 'Not provided'; + + if (!empty($definition['rights'])) { + $license = $definition['rights']; + } + + if (!empty($definition['theme'])) { + $theme = $definition['theme']; + } + + // Get the target audience and category. + $segments = $request->segments(); + + if (count($segments) >= 2 && !in_array($segments[0], $this->IGNORE)) { + // The URL of the GA + $url = 'http://www.google-analytics.com/collect'; + + // The version of the Google Analytics Measurement Protocol. + $data['v'] = 1; + + // The tracker ID. + $data['tid'] = $tracker_id; + + // GA requires a user ID, but since all requests are anonymous + // we generate a unique string to use as ID. + $data['cid'] = sprintf( + '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', + mt_rand(0, 0xffff), + mt_rand(0, 0xffff), + mt_rand(0, 0xffff), + mt_rand(0, 0x0fff) | 0x4000, + mt_rand(0, 0x3fff) | 0x8000, + mt_rand(0, 0xffff), + mt_rand(0, 0xffff), + mt_rand(0, 0xffff) + ); + + // The type of 'hit', in this case we use pageview. + $data['t'] = 'pageview'; + + // The url to track, required when using 'pageview' as type. + $data['dp'] = $path; + $data['cd1'] = $extension; + $data['cd2'] = $theme; + $data['cd3'] = $license; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); + curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, utf8_encode(http_build_query($data))); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $response = curl_exec($ch); + curl_close($ch); + } + } +} diff --git a/app/Tdt/Core/Analytics/TrackerInterface.php b/app/Tdt/Core/Analytics/TrackerInterface.php new file mode 100644 index 00000000..5a1b5906 --- /dev/null +++ b/app/Tdt/Core/Analytics/TrackerInterface.php @@ -0,0 +1,8 @@ + */ - abstract class ApiController extends \Controller { diff --git a/app/Tdt/Core/BaseController.php b/app/Tdt/Core/BaseController.php index fc67f8bf..53e60cbd 100644 --- a/app/Tdt/Core/BaseController.php +++ b/app/Tdt/Core/BaseController.php @@ -23,14 +23,13 @@ public function handleRequest($uri) $uri = strtolower(rtrim($uri, '/')); // Check first segment of the request - switch(\Request::segment(1)){ + switch (\Request::segment(1)) { case 'discovery': // Discovery document $controller = 'Tdt\\Core\\Definitions\\DiscoveryController'; break; case 'api': - switch(\Request::segment(2)){ - + switch (\Request::segment(2)) { case 'definitions': // Definitions request $controller = 'Tdt\\Core\\Definitions\\DefinitionController'; @@ -51,6 +50,10 @@ public function handleRequest($uri) $controller = 'Tdt\\Core\\Definitions\\LanguageController'; $uri = str_replace('api/languages', '', $uri); break; + case 'geoprojections': + $controller = 'Tdt\\Core\\Definitions\\GeoprojectionController'; + $uri = str_replace('api/geoprojections', '', $uri); + break; case 'licenses': // Supported licenses request $controller = 'Tdt\\Core\\Definitions\\LicenseController'; @@ -71,15 +74,6 @@ public function handleRequest($uri) break; } - break; - case 'discovery': - // Discovery document - $controller = 'Tdt\\Core\\Definitions\\DiscoveryController'; - break; - case 'spectql': - // SPECTQL request - $uri = str_ireplace('spectql', '', $original_uri); - $controller = 'Tdt\\Core\\Definitions\\SpectqlController'; break; case '': // Home URL requests @@ -99,6 +93,8 @@ public function handleRequest($uri) if ($response instanceof \Illuminate\Http\RedirectResponse) { // Redirect and that's it return $response; + } else if ($response instanceof \Symfony\Component\HttpFoundation\BinaryFileResponse) { + return $response; } else { // Make sure cross origin requests are allowed for GET $response->header('Access-Control-Allow-Origin', '*'); diff --git a/app/Tdt/Core/Commands/DcatLicenses.php b/app/Tdt/Core/Commands/DcatLicenses.php new file mode 100644 index 00000000..57986df7 --- /dev/null +++ b/app/Tdt/Core/Commands/DcatLicenses.php @@ -0,0 +1,183 @@ +seedLicenses(); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array( + array('name', InputArgument::OPTIONAL, 'The name of the licenses document hosted on https://github.com/tdt/licenses that should be seeded into the datatank. Default value is international_licenses.', $this->DEFAULT_LICENSE), + ); + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return array( + ); + } + + /** + * Seed the themes + * + * @return @void + */ + private function seedLicenses() + { + $this->info('---- Seeding new licenses ----'); + + $license_name = $this->argument('name'); + + $license_uri = $this->licenses_uri . $license_name; + + if (substr($license_uri, -5) != '.json') { + $license_uri .= '.json'; + } + + // Try to get the themes from the ns.thedatatank.com (semantic data) + try { + $this->info('Trying to fetch triples from the uri: ' . $license_uri); + + try { + $licenses_graph = \EasyRdf_Graph::newAndLoad($license_uri, 'jsonld'); + } catch (\EasyRdf_Http_Exception $ex) { + $this->info('We could not fetch licenses from the URL ' . $license_uri . ', defaulting to ' . $this->DEFAULT_LICENSE . '.'); + + $licenses_graph = $this->fetchDefaultGraph(); + } + + if ($licenses_graph->isEmpty()) { + $this->info('We could not fetch licenses from the URL ' . $license_uri . ', defaulting to ' . $this->DEFAULT_LICENSE . '.'); + + $licenses_graph = $this->fetchDefaultGraph(); + + } else { + $this->info('Fetched new licenses, removing the old ones.'); + + // Empty the licenses table + \License::truncate(); + } + + // Fetch the resources with a skos:conceptScheme relationship + $licenses = $licenses_graph->allOfType('cc:License'); + + $taxonomy_uris = array(); + + foreach ($licenses as $license) { + $url = ''; + $title = ''; + $identifier = ''; + + $title_resource = $license->getLiteral('dc:title'); + $identifier_resource = $license->getLiteral('dc:identifier'); + + if (!empty($title_resource)) { + $title = $title_resource->getValue(); + } + + if (!empty($identifier_resource)) { + $identifier = $identifier_resource->getValue(); + } + + if (!$license->isBNode()) { + $url = $license->getUri(); + } + + \License::create([ + 'url' => $url, + 'title' => $title, + 'license_id' => $identifier + ]); + + $this->info('Added license "' . $identifier . '" with title "' . $title . '" and URI ' . $url); + } + + } catch (EasyRdf_Exception $ex) { + $this->info('An error occurred when we tried to fetch online themes.'); + } + } + + /** + * Fetch the default licenses + * + * @return \EasyRdf_Graph + */ + private function fetchDefaultGraph() + { + $license_uri = $this->licenses_uri . $this->DEFAULT_LICENSE . '.json'; + + return \EasyRdf_Graph::newAndLoad($license_uri, 'jsonld'); + } +} diff --git a/app/Tdt/Core/Commands/DcatThemes.php b/app/Tdt/Core/Commands/DcatThemes.php index aa7976e9..06f16c16 100644 --- a/app/Tdt/Core/Commands/DcatThemes.php +++ b/app/Tdt/Core/Commands/DcatThemes.php @@ -19,7 +19,7 @@ class DcatThemes extends Command * * @var string */ - protected $name = 'datatank:theme'; + protected $name = 'datatank:themes'; /** * The console command description. diff --git a/app/Tdt/Core/Commands/GeoProjections.php b/app/Tdt/Core/Commands/GeoProjections.php new file mode 100644 index 00000000..6153722e --- /dev/null +++ b/app/Tdt/Core/Commands/GeoProjections.php @@ -0,0 +1,122 @@ +ask("What do you want to do (pass number). (1) Reseed the geo projections (2) Add a geo projection "); + + if ($option == 1) { + $this->seedGeoprojections(); + } elseif ($option == 2) { + $epsg = $this->ask("Enter the EPSG code: "); + $projection = $this->ask("Enter the projection string (in OGC WKT format): "); + + \Geoprojection::create([ + 'epsg' => $epsg, + 'projection' => $projection + ]); + } else { + $this->error("Option $option is not supported."); + } + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array( + ); + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return array( + ); + } + + /** + * Seed the themes + * + * return @void + */ + private function seedGeoprojections() + { + $this->info('---- Geo projections ----'); + + $this->info('Fetching geoprojections from the local json file.'); + + $geoprojections = json_decode(file_get_contents(app_path() . '/database/seeds/data/geoprojections.json')); + + if (!empty($geoprojections)) { + $this->info('Geoprojections have been found, deleting the current ones, and replacing them with the new ones.'); + + \Geoprojection::truncate(); + + foreach ($geoprojections as $language) { + \Geoprojection::create(array( + 'epsg' => $language->epsg, + 'projection' =>$language->projection, + )); + } + + $this->info('Added the geoprojections from a local json file.'); + + } else { + $this->info('No geoprojections have not been found in the file, the old ones will not be replaced.'); + } + } +} diff --git a/app/Tdt/Core/ContentNegotiator.php b/app/Tdt/Core/ContentNegotiator.php index 4fd13d06..21743010 100644 --- a/app/Tdt/Core/ContentNegotiator.php +++ b/app/Tdt/Core/ContentNegotiator.php @@ -33,7 +33,8 @@ class ContentNegotiator extends Pager ), 'ttl' => array('text/turtle'), 'nt' => array('application/n-triples'), - 'jsonld' => array('application/ld+json') + 'jsonld' => array('application/ld+json'), + 'geojson' => array('application/vnd.geo+json'), ); /** @@ -56,7 +57,6 @@ public static function getResponse($data, $extension = null) $formatter_class = 'Tdt\\Core\\Formatters\\' . $extension . 'Formatter'; if (empty($extension)) { - $negotiator = new FormatNegotiator(); foreach (self::$mime_types_map as $format_name => $mime_types) { @@ -101,7 +101,6 @@ public static function getResponse($data, $extension = null) $format_object = $negotiator->getBest($accept_header, $priorities); if (!$format || $format_object->getQuality() == 0) { - $format_helper = new FormatHelper(); $available_formats = implode(', ', array_values($format_helper->getAvailableFormats($data))); @@ -114,8 +113,7 @@ public static function getResponse($data, $extension = null) // Formatter class $formatter_class = 'Tdt\\Core\\Formatters\\' . $extension . 'Formatter'; - } else if (!class_exists($formatter_class)) { - + } elseif (!class_exists($formatter_class)) { $format_helper = new FormatHelper(); $available_formats = implode(', ', array_values($format_helper->getAvailableFormats($data))); @@ -133,7 +131,6 @@ public static function getResponse($data, $extension = null) // Set the URI template header if (!empty($data->optional_parameters) || !empty($data->rest_parameters)) { - // http://www.mnot.net/blog/2006/10/04/uri_templating $link_template = self::fetchUrl($extension); @@ -153,7 +150,6 @@ public static function getResponse($data, $extension = null) // Add the optional parameters if (!empty($data->optional_parameters)) { - $link_template .= '{?'; foreach ($data->optional_parameters as $optional_parameter) { @@ -171,7 +167,6 @@ public static function getResponse($data, $extension = null) $cache_minutes = -1; if (\Config::get('cache.enabled', true)) { - $cache_minutes = 1; // Cache per resource diff --git a/app/Tdt/Core/DataControllers/ADataController.php b/app/Tdt/Core/DataControllers/ADataController.php index 291d9792..a989caa4 100644 --- a/app/Tdt/Core/DataControllers/ADataController.php +++ b/app/Tdt/Core/DataControllers/ADataController.php @@ -12,7 +12,6 @@ */ abstract class ADataController { - protected static $DEFAULT_PAGE_SIZE = 350; abstract public function readData($source_definitions, $rest_parameters = array()); diff --git a/app/Tdt/Core/DataControllers/CSVController.php b/app/Tdt/Core/DataControllers/CSVController.php index bce2c8fe..c50556db 100644 --- a/app/Tdt/Core/DataControllers/CSVController.php +++ b/app/Tdt/Core/DataControllers/CSVController.php @@ -60,19 +60,16 @@ public function readData($source_definition, $rest_parameters = array()) // Check if they match with the freshly parsed columns if (count($parsed_columns) != count($columns)) { - // Save the new config $this->tabular_columns->deleteBulk($source_definition['id'], 'CsvDefinition'); $this->tabular_columns->storeBulk($source_definition['id'], 'CsvDefinition', $columns); } else { foreach ($parsed_columns as $parsed_column) { - $column = array_shift($columns); foreach ($parsed_column as $key => $val) { if ($val != $column[$key]) { - // Save the new config $this->tabular_columns->deleteBulk($source_definition['id'], 'CsvDefinition'); $this->tabular_columns->storeBulk($source_definition['id'], 'CsvDefinition', $columns); @@ -106,7 +103,6 @@ public function readData($source_definition, $rest_parameters = array()) $pk = null; foreach ($columns as $column) { - if (!empty($column['is_pk'])) { $pk = $column['column_name_alias']; } @@ -127,17 +123,13 @@ public function readData($source_definition, $rest_parameters = array()) $hits = 0; if (($handle = fopen($uri, "r")) !== false) { - while (($data = fgetcsv($handle, 2000000, $delimiter)) !== false) { - if ($total_rows >= $start_row) { - // Create the values array, containing the (aliased) name of the column // to the value of a the row which $data represents $values = $this->createValues($columns, $data); if ($offset <= $hits && $offset + $limit > $hits) { - $obj = new \stdClass(); foreach ($values as $key => $value) { @@ -147,7 +139,6 @@ public function readData($source_definition, $rest_parameters = array()) if (empty($pk)) { array_push($row_objects, $obj); } else { - if (!empty($row_objects[$obj->$pk])) { \Log::info("The primary key $pk has been used already for another record!"); } else { @@ -159,6 +150,10 @@ public function readData($source_definition, $rest_parameters = array()) } $total_rows++; + + if ($total_rows >= 10000) { + break; + } } fclose($handle); @@ -188,11 +183,8 @@ private function createValues($columns, $data) if (!empty($data[$column['index']]) || is_numeric(@$data[$column['index']])) { $result[$column['column_name_alias']] = @$data[$column['index']]; } else { - $index = $column['index']; - \Log::warning("We expected a value for index $index, yet no value was given. Filling in an empty value."); - $result[$column['column_name_alias']] = ''; } } @@ -223,7 +215,6 @@ public static function parseColumns($config) $columns = array(); if (($handle = fopen($config['uri'], "r")) !== false) { - // Throw away the lines untill we hit the start row // from then on, process the columns $commentlinecounter = 0; @@ -236,9 +227,7 @@ public static function parseColumns($config) $index = 0; if (($line = fgetcsv($handle, 0, $config['delimiter'], '"')) !== false) { - if (sizeof($line) <= 1) { - $delimiter = $config['delimiter']; $uri = $config['uri']; @@ -248,7 +237,6 @@ public static function parseColumns($config) $index++; for ($i = 0; $i < sizeof($line); $i++) { - // Try to get an alias from the config, if it's empty // then just take the column value as alias $alias = @$aliases[$i]; diff --git a/app/Tdt/Core/DataControllers/ELASTICSEARCHController.php b/app/Tdt/Core/DataControllers/ELASTICSEARCHController.php new file mode 100644 index 00000000..ea94cba6 --- /dev/null +++ b/app/Tdt/Core/DataControllers/ELASTICSEARCHController.php @@ -0,0 +1,80 @@ + + */ +class ELASTICSEARCHController extends ADataController +{ + public function readData($source_definition, $rest_parameters = []) + { + list($limit, $offset) = Pager::calculateLimitAndOffset(); + + $query_param = \Input::get('query', '*'); + + // Check for authentication + if (!empty($source_definition['username']) && !empty($source_definition['password'])) { + $auth = $source_definition['username'] . ':' . $source_definition['password'] . '@'; + + $parts = parse_url($source_definition['host']); + + if ($parts['scheme'] == 'https') { + $schemeless_url = str_replace('https://', '', $source_definition['host']); + $source_definition['host'] = 'https://' . $auth . $schemeless_url; + } else { + $schemeless_url = str_replace('http://', '', $source_definition['host']); + $source_definition['host'] = 'http://' . $auth . $schemeless_url; + } + } + + $hosts = ['hosts' => [$source_definition['host'] . ':' . $source_definition['port']]]; + $client = new Client($hosts); + + $search_params = []; + $search_params['index'] = $source_definition['es_index']; + $search_params['type'] = $source_definition['es_type']; + $search_params['body']['query']['query_string']['query'] = $query_param; + + $results = $client->search($search_params); + $data = []; + $data_result = new Data(); + + if (!empty($results['hits']['total'])) { + $paging = Pager::calculatePagingHeaders($limit, $offset, $results['hits']['total']); + + $filtered_hits = []; + + foreach ($results['hits']['hits'] as $hit) { + $filtered_hits[] = $hit['_source']; + } + + $data_result->data = $filtered_hits; + } else { + $data_result->data = []; + $data_result->paging = []; + } + + $data_result->preferred_formats = $this->getPreferredFormats(); + + return $data_result; + } + + public static function getParameters() + { + $query_params = [ + "query" => [ + "required" => false, + "description" => "A value that will be used to perform a full text-search on the data." + ] + ]; + + return array_merge($query_params, parent::getParameters()); + } +} diff --git a/app/Tdt/Core/DataControllers/JSONController.php b/app/Tdt/Core/DataControllers/JSONController.php index 49d5ef84..65ad065a 100644 --- a/app/Tdt/Core/DataControllers/JSONController.php +++ b/app/Tdt/Core/DataControllers/JSONController.php @@ -23,34 +23,65 @@ public static function getParameters() public function readData($source_definition, $rest_parameters = array()) { - $uri = $source_definition['uri']; - // Check for caching - if (Cache::has($uri)) { - $data = Cache::get($uri); - } else { - // Fetch the data - $data = []; - - if (!filter_var($uri, FILTER_VALIDATE_URL) === false) { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $uri); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $data = curl_exec($ch); - curl_close($ch); - } else { - $data =@ file_get_contents($uri); - } + $this->cache = $source_definition['cache']; + + switch ($source_definition['jsontype']) { + case 'GeoJSON': + return $this->makeGeoResponse($uri); + break; + case 'JSON-LD': + return $this->makeSemanticResponse($uri); + break; + default: + return $this->makePlainResponse($uri); + break; + } + } + + private function makeGeoResponse($uri) + { + $data = $this->getPlainJson($uri); + + $php_object = json_decode($data); + + $data_result = new Data(); + $data_result->data = $php_object; + $data_result->preferred_formats = ['geojson']; + $data_result->geo_formatted = true; + + return $data_result; + } + + private function makeSemanticResponse($uri) + { + try { + $graph = new \EasyRdf_Graph(); - if ($data) { - Cache::put($uri, $data, $source_definition['cache']); + if ((substr($uri, 0, 4) == "http")) { + $graph = \EasyRdf_Graph::newAndLoad($uri); } else { - $uri = $source_definition['uri']; - \App::abort(500, "Cannot retrieve data from the JSON file located on $uri."); + $graph->parseFile($uri, 'jsonld'); } + + } catch (\Exception $ex) { + \App::abort(500, "The JSON-LD reader couldn't parse the document, the exception message we got is: " . $ex->getMessage()); } + // Return the data object with the graph + $data = new Data(); + $data->data = $graph; + $data->is_semantic = true; + $data->preferred_formats = ['jsonld', 'ttl', 'rdf']; + + return $data; + } + + private function makePlainResponse($uri) + { + $data = $this->getPlainJson($uri); + $php_object = json_decode($data); $data_result = new Data(); @@ -59,4 +90,32 @@ public function readData($source_definition, $rest_parameters = array()) return $data_result; } + + private function getPlainJson($uri) + { + $data = []; + + if (Cache::has($uri)) { + return Cache::get($uri); + } + + if (!filter_var($uri, FILTER_VALIDATE_URL) === false) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $uri); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $data = curl_exec($ch); + curl_close($ch); + } else { + $data =@ file_get_contents($uri); + } + + if ($data) { + Cache::put($uri, $data, $this->cache); + } else { + $uri = $source_definition['uri']; + \App::abort(500, "Cannot retrieve data from the JSON file located on $uri."); + } + + return $data; + } } diff --git a/app/Tdt/Core/DataControllers/JSONLDController.php b/app/Tdt/Core/DataControllers/JSONLDController.php deleted file mode 100644 index d502dba5..00000000 --- a/app/Tdt/Core/DataControllers/JSONLDController.php +++ /dev/null @@ -1,56 +0,0 @@ - - */ -class JSONLDController extends ADataController -{ - public static function getParameters() - { - return []; - } - - public function readData($source_definition, $rest_parameters = array()) - { - $uri = $source_definition['uri']; - - // If the parsing in the document fails, a JsonLdException is thrown - try { - - $graph = new \EasyRdf_Graph(); - - if ((substr($uri, 0, 4) == "http")) { - $graph = \EasyRdf_Graph::newAndLoad($uri); - } else { - $graph->parseFile($uri, 'jsonld'); - } - - } catch (\Exception $ex) { - \App::abort(500, "The JSON LD reader couldn't parse the document, the exception message we got is: " . $ex->getMessage()); - } - - // Return the data object with the graph - $data = new Data(); - $data->data = $graph; - $data->is_semantic = true; - $data->preferred_formats = $this->getPreferredFormats(); - - return $data; - } - - protected function getPreferredFormats() - { - return array('jsonld', 'ttl', 'rdf'); - } -} diff --git a/app/Tdt/Core/DataControllers/MONGOController.php b/app/Tdt/Core/DataControllers/MONGOController.php new file mode 100644 index 00000000..02ddde35 --- /dev/null +++ b/app/Tdt/Core/DataControllers/MONGOController.php @@ -0,0 +1,85 @@ + + */ +class MONGOController extends ADataController +{ + public function readData($source_definition, $rest_parameters = []) + { + list($limit, $offset) = Pager::calculateLimitAndOffset(); + + $collection = $this->getCollection($source_definition); + + // Parse the parameters from the query string (prefixed by q.) + $all_parameters = \Input::get(); + + $query = []; + + foreach ($all_parameters as $key => $val) { + if (substr($key, 0, 2) == 'q_') { + $key = str_replace('q_', '', $key); + $query[$key] = $val; + } + } + + $total_objects = $collection->count($query); + + $cursor = $collection->find($query)->skip($offset)->limit($limit); + + $results = []; + + foreach ($cursor as $result) { + unset($result['_id']); + + $results[] = $result; + } + + $paging = Pager::calculatePagingHeaders($limit, $offset, $total_objects); + + $data_result = new Data(); + $data_result->data = $results; + $data_result->paging = $paging; + $data_result->preferred_formats = $this->getPreferredFormats(); + + return $data_result; + } + + /** + * Create and return a MongoCollection + * + * @param array $source_definition The configuration for the mongo resource + * + * @return \MongoCollection + */ + private function getCollection($source_definition) + { + $prefix = ''; + $auth = []; + + if (!empty($source_definition['username'])) { + $auth['username'] = $source_definition['username']; + $auth['password'] = $source_definition['password']; + } + + $conn_string = 'mongodb://' . $source_definition['host'] . ':' . $source_definition['port'] . '/' . $source_definition['database']; + + try { + $client = new MongoClient($conn_string, $auth); + } catch (\MongoConnectionException $ex) { + \App::abort(500, 'Could not create a connection with the MongoDB, please check if the configuration is still ok.'); + } + + $mongoCollection = $client->selectCollection($source_definition['database'], $source_definition['mongo_collection']); + + return $mongoCollection; + } +} diff --git a/app/Tdt/Core/DataControllers/MYSQLController.php b/app/Tdt/Core/DataControllers/MYSQLController.php index cba6e178..202f2f7f 100644 --- a/app/Tdt/Core/DataControllers/MYSQLController.php +++ b/app/Tdt/Core/DataControllers/MYSQLController.php @@ -89,7 +89,6 @@ public function readData($source_definition, $rest_parameters = array()) $db = \DB::connection('mysqltmp'); try { - $query = $source_definition['query']; // Get the total amount of records for the query for pagination @@ -106,7 +105,6 @@ public function readData($source_definition, $rest_parameters = array()) $total_rows = $count_result[0]->count; if (!$limitInQuery) { - if (!empty($limit)) { $query .= ' limit ' . $limit; } diff --git a/app/Tdt/Core/DataControllers/SHPController.php b/app/Tdt/Core/DataControllers/SHPController.php index 8b245848..a9ce04d9 100644 --- a/app/Tdt/Core/DataControllers/SHPController.php +++ b/app/Tdt/Core/DataControllers/SHPController.php @@ -10,13 +10,15 @@ namespace Tdt\Core\DataControllers; +use proj4php\Proj; +use proj4php\Proj4php; +use proj4php\Point; use Tdt\Core\Datasets\Data; use Tdt\Core\Pager; use Tdt\Core\Repositories\Interfaces\TabularColumnsRepositoryInterface; use Tdt\Core\Repositories\Interfaces\GeoPropertyRepositoryInterface; use muka\ShapeReader\ShapeReader; - -//include_once(app_path() . "/lib/ShapeFile.inc.php"); +use Tdt\Core\Repositories\Interfaces\GeoprojectionRepositoryInterface; class SHPController extends ADataController { @@ -24,10 +26,26 @@ class SHPController extends ADataController private $tabular_columns; private $geo_property; - public function __construct(TabularColumnsRepositoryInterface $tabular_columns, GeoPropertyRepositoryInterface $geo_property) - { + private static $RECORD_TYPES = [ + 0 => "Null Shape", + 1 => "Point", + 3 => "PolyLine", + 5 => "Polygon", + 8 => "MultiPoint", + 11 => "PointZ", + 13 => "PolyLineZ", + 15 => "PolygonZ", + 18 => "MultiPointZ" + ]; + + public function __construct( + TabularColumnsRepositoryInterface $tabular_columns, + GeoPropertyRepositoryInterface $geo_property, + GeoprojectionRepositoryInterface $projections + ) { $this->tabular_columns = $tabular_columns; $this->geo_property = $geo_property; + $this->projections = $projections; } public function readData($source_definition, $rest_parameters = array()) @@ -48,7 +66,7 @@ public function readData($source_definition, $rest_parameters = array()) $columns = array(); - $epsg = $source_definition['epsg']; + $this->epsg = $source_definition['epsg']; // The tmp folder of the system, if none is given // abort the process @@ -76,7 +94,6 @@ public function readData($source_definition, $rest_parameters = array()) } try { - // Create the array in which all the resulting objects will be placed $arrayOfRowObjects = array(); @@ -87,7 +104,6 @@ public function readData($source_definition, $rest_parameters = array()) // If the shape files are located on an HTTP address, fetch them and store them locally if ($is_url) { - $tmp_file_name = uniqid(); $tmp_file = $tmp_path . "/" . $tmp_file_name; @@ -98,7 +114,6 @@ public function readData($source_definition, $rest_parameters = array()) // Along this file the class will use file.shx and file.dbf $shp = new ShapeReader($tmp_file . ".shp", $options); } else { - $shp = new ShapeReader($uri, $options); // along this file the class will use file.shx and file.dbf } @@ -107,9 +122,7 @@ public function readData($source_definition, $rest_parameters = array()) // Get the shape records in the binary file while ($record = $shp->getNext()) { - if ($offset <= $total_rows && $offset + $limit > $total_rows) { - // Every shape record is parsed as an anonymous object with the properties attached to it $rowobject = new \stdClass(); @@ -117,7 +130,6 @@ public function readData($source_definition, $rest_parameters = array()) $dbf_data = $record->getDbfData(); foreach ($dbf_data as $property => $value) { - $property_alias = $columns[$property]; $property = trim($property); $property_alias = $columns[$property]; @@ -127,84 +139,290 @@ public function readData($source_definition, $rest_parameters = array()) // Read the shape data $shp_data = $record->getShpData(); - if (!empty($epsg)) { - $proj4 = new \Proj4php(); - $projSrc = new \Proj4phpProj('EPSG:'. $epsg, $proj4); - $projDest = new \Proj4phpProj('EPSG:4326', $proj4); + $shape_type = self::$RECORD_TYPES[$record->getTypeCode()]; + + // Get the projection code + $projection = $this->projections->getByCode($this->epsg); + $projCode = $projection['projection']; + + if (empty($projCode)) { + \App::abort(400, "Could not find a supported EPSG code."); } - // It it's not a point, it's a collection of coordinates describing a shape - if (!empty($shp_data['parts'])) { + $this->proj4 = new Proj4php(); + + $this->projSrc = new Proj('EPSG:' . $this->epsg, $this->proj4); + $this->projDest = new Proj('EPSG:4326', $this->proj4); + + $geometry = []; + + switch (strtolower($shape_type)) { + case 'point': + $point = $this->parsePoint($shp_data); + + $rowobject->x = $point['x']; + $rowobject->y = $point['y']; + break; + case 'polyline': + $rowobject->parts = $this->parsePolyline($shp_data); + break; + case 'polygon': + $rowobject->parts = $this->parsePolygon($shp_data); + break; + case 'multipoint': + $rowobject->points = $this->parseMultipoint($shp_data); + break; + case 'pointz': + $point = $this->parsePointZ($shp_data); + + $rowobject->x = $point['x']; + $rowobject->y = $point['y']; + $rowobject->z = $point['z']; + break; + case 'polylinez': + $rowobject->parts = $this->parsePolylineZ($shp_data); + break; + case 'polygonz': + $rowobject->parts = $this->parsePolygonZ($shp_data); + break; + case 'multipointz': + $rowobject->points = $this->parseMultiPointZ($shp_data); + break; + } - $parts = array(); + array_push($arrayOfRowObjects, $rowobject); + } - foreach ($shp_data['parts'] as $part) { + $total_rows++; - $points = array(); + if ($total_rows >= 10000) { + break; + } + } - foreach ($part['points'] as $point) { + // Calculate the paging headers properties + $paging = Pager::calculatePagingHeaders($limit, $offset, $total_rows); - $x = $point['x']; - $y = $point['y']; + $data_result = new Data(); + $data_result->data = $arrayOfRowObjects; + $data_result->geo = $geo; + $data_result->paging = $paging; + $data_result->preferred_formats = array('map', 'geojson'); - // Translate the coordinates to WSG84 geo coordinates - if (!empty($epsg)) { + return $data_result; + } catch (Exception $ex) { + \App::abort(500, "Something went wrong while putting the SHP files in a temporary directory or during the extraction of the SHP data. The error message is: $ex->getMessage()."); + } + } - $pointSrc = new \proj4phpPoint($x, $y); + private function parsePoint($shp_data) + { + // x = long, y = lat + $x = $shp_data['x']; + $y = $shp_data['y']; - $pointDest = $proj4->transform($projSrc, $projDest, $pointSrc); - $x = $pointDest->x; - $y = $pointDest->y; - } + if (!empty($x) && !empty($y)) { + if (!empty($this->epsg) && $this->epsg != 4326) { + $pointSrc = new Point($x, $y); - $points[] = $x.','.$y; - } - array_push($parts, implode(" ", $points)); - } + $pointDest = $this->proj4->transform($this->projSrc, $this->projDest, $pointSrc); + $x = $pointDest->x; + $y = $pointDest->y; + } - // Parts only contains 1 shape, thus 1 geo entry - $alias = reset($geo); + $geo['x'] = $x; + $geo['y'] = $y; + } - $rowobject->$alias = implode(';', $parts); - } + return $geo; + } - if (isset($shp_data['x'])) { + private function parsePointZ($shp_data) + { + // x = long, y = lat + $x = $shp_data['x']; + $y = $shp_data['y']; + $z = $shp_data['z']; + + if (!empty($x) && !empty($y) && !empty($z)) { + if (!empty($this->epsg) && $this->epsg != 4326) { + $pointSrc = new Point($x, $y, $z); + + $pointDest = $this->proj4->transform($this->projSrc, $this->projDest, $pointSrc); + $x = $pointDest->x; + $y = $pointDest->y; + $z = $pointDest->z; + } - $x = $shp_data['x']; - $y = $shp_data['y']; + $geo['x'] = $x; + $geo['y'] = $y; + $geo['z'] = $z; + } - if (!empty($epsg)) { + return $geo; + } - $pointSrc = new \proj4phpPoint($x, $y); - $pointDest = $proj4->transform($projSrc, $projDest, $pointSrc); - $x = $pointDest->x; - $y = $pointDest->y; + private function parsePolyline($shp_data) + { + $parts = array(); - } + foreach ($shp_data['parts'] as $part) { + $points = array(); - $rowobject->$geo['longitude'] = $x; - $rowobject->$geo['latitude'] = $y; - } - array_push($arrayOfRowObjects, $rowobject); + foreach ($part['points'] as $point) { + $x = $point['x']; + $y = $point['y']; + + // Translate the coordinates to WSG84 geo coordinates + if (!empty($this->epsg)) { + $pointSrc = new Point($x, $y); + + $pointDest = $this->proj4->transform($this->projSrc, $this->projDest, $pointSrc); + $x = $pointDest->x; + $y = $pointDest->y; } - $total_rows++; + + $points[] = $x . ',' . $y; } + array_push($parts, implode(" ", $points)); + } - // Calculate the paging headers properties - $paging = Pager::calculatePagingHeaders($limit, $offset, $total_rows); + return implode(';', $parts); + } - $data_result = new Data(); - $data_result->data = $arrayOfRowObjects; - $data_result->geo = $geo; - $data_result->paging = $paging; - $data_result->preferred_formats = array('map'); + private function parsePolylineZ($shp_data) + { + $parts = array(); - return $data_result; + foreach ($shp_data['parts'] as $part) { + $points = array(); - } catch (Exception $ex) { + foreach ($part['points'] as $point) { + $x = $point['x']; + $y = $point['y']; + $z = $point['z']; - \App::abort(500, "Something went wrong while putting the SHP files in a temporary directory or during the extraction of the SHP data. The error message is: $ex->getMessage()."); + // Translate the coordinates to WSG84 geo coordinates + if (!empty($this->epsg)) { + $pointSrc = new Point($x, $y, $z); + + $pointDest = $this->proj4->transform($this->projSrc, $this->projDest, $pointSrc); + $x = $pointDest->x; + $y = $pointDest->y; + } + + $points[] = $x . ',' . $y . ',' . $z; + } + array_push($parts, implode(" ", $points)); } + + return implode(';', $parts); + } + + private function parsePolygon($shp_data) + { + $parts = array(); + + foreach ($shp_data['parts'] as $part) { + $points = array(); + + foreach ($part['points'] as $point) { + $x = $point['x']; + $y = $point['y']; + + // Translate the coordinates to WSG84 geo coordinates + if (!empty($this->epsg)) { + $pointSrc = new Point($x, $y); + + $pointDest = $this->proj4->transform($this->projSrc, $this->projDest, $pointSrc); + $x = $pointDest->x; + $y = $pointDest->y; + } + + $points[] = $x . ',' . $y; + } + array_push($parts, implode(" ", $points)); + } + + return $parts = implode(';', $parts); + } + + private function parsePolygonZ($shp_data) + { + $parts = array(); + + foreach ($shp_data['parts'] as $part) { + $points = array(); + + foreach ($part['points'] as $point) { + $x = $point['x']; + $y = $point['y']; + $z = $point['z']; + + // Translate the coordinates to WSG84 geo coordinates + if (!empty($this->epsg)) { + $pointSrc = new Point($x, $y, $z); + + $pointDest = $this->proj4->transform($this->projSrc, $this->projDest, $pointSrc); + $x = $pointDest->x; + $y = $pointDest->y; + $z = $pointDest->z; + } + + $points[] = $x . ',' . $y . ',' . $z; + } + array_push($parts, implode(" ", $points)); + } + + return $parts = implode(';', $parts); + } + + private function parseMultipoint($shp_data) + { + foreach ($shp_data['points'] as $point) { + $x = $point['x']; + $y = $point['y']; + + if (!empty($x) && !empty($y)) { + if (!empty($this->epsg)) { + $pointSrc = new Point($x, $y); + + $pointDest = $this->proj4->transform($this->projSrc, $this->projDest, $pointSrc); + + $x = $pointDest->x; + $y = $pointDest->y; + } + + $points[] = $x . ',' . $y; + } + } + + return implode(';', $points); + } + + private function parseMultipointZ($shp_data) + { + foreach ($shp_data['points'] as $point) { + $x = $point['x']; + $y = $point['y']; + $z = $point['z']; + + if (!empty($x) && !empty($y) && !empty($z)) { + if (!empty($this->epsg)) { + $pointSrc = new Point($x, $y, $z); + + $pointDest = $this->proj4->transform($this->projSrc, $this->projDest, $pointSrc); + + $x = $pointDest->x; + $y = $pointDest->y; + $z = $pointDest->z; + } + + $points[] = $x . ',' . $y . ',' . $z; + } + } + + return implode(';', $points); } /** @@ -220,7 +438,6 @@ public static function parseColumns($options) try { if ($is_url) { - // This remains untested $tmp_file = uniqid(); @@ -231,7 +448,6 @@ public static function parseColumns($options) // Along this file the class will use file.shx and file.dbf $shp = new ShapeReader($tmp_dir . '/' . $tmp_file . ".shp", array('noparts' => false)); } else { - // along this file the class will use file.shx and file.dbf $shp = new ShapeReader($options['uri'], array('noparts' => false)); } @@ -253,7 +469,6 @@ public static function parseColumns($options) $column_index = 0; foreach ($dbf_fields as $field => $value) { - // Remove non-printable characters $property = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $field); @@ -261,18 +476,37 @@ public static function parseColumns($options) $column_index++; } - $shp_data = $record->getShpData(); + $shape_type = self::$RECORD_TYPES[$record->getTypeCode()]; // Get the geographical column names - // Either coords will be set (identified by the parts) - // or a lat long will be set (identified by x and y) - if (!empty($shp_data['parts'])) { - array_push($columns, array('index' => $column_index, 'column_name' => 'parts', 'column_name_alias' => 'parts', 'is_pk' => 0)); - } elseif (!empty($shp_data['x'])) { - array_push($columns, array('index' => $column_index, 'column_name' => 'x', 'column_name_alias' => 'x', 'is_pk' => 0)); - array_push($columns, array('index' => $column_index + 1, 'column_name' => 'y', 'column_name_alias' => 'y', 'is_pk' => 0)); - } else { - \App::abort(400, 'The shapefile could not be processed, probably because the geometry in the shape file is not supported. The supported geometries are Null Shape, Point, PolyLine, Polygon and MultiPoint'); + switch (strtolower($shape_type)) { + case 'point': + array_push($columns, array('index' => $column_index, 'column_name' => 'x', 'column_name_alias' => 'x', 'is_pk' => 0)); + array_push($columns, array('index' => $column_index + 1, 'column_name' => 'y', 'column_name_alias' => 'y', 'is_pk' => 0)); + break; + case 'polyline': + array_push($columns, array('index' => $column_index, 'column_name' => 'parts', 'column_name_alias' => 'parts', 'is_pk' => 0)); + break; + case 'polygon': + array_push($columns, array('index' => $column_index, 'column_name' => 'parts', 'column_name_alias' => 'parts', 'is_pk' => 0)); + break; + case 'multipoint': + array_push($columns, array('index' => $column_index, 'column_name' => 'points', 'column_name_alias' => 'points', 'is_pk' => 0)); + break; + case 'pointz': + array_push($columns, array('index' => $column_index, 'column_name' => 'x', 'column_name_alias' => 'x', 'is_pk' => 0)); + array_push($columns, array('index' => $column_index + 1, 'column_name' => 'y', 'column_name_alias' => 'y', 'is_pk' => 0)); + array_push($columns, array('index' => $column_index + 2, 'column_name' => 'z', 'column_name_alias' => 'z', 'is_pk' => 0)); + break; + case 'polylinez': + array_push($columns, array('index' => $column_index, 'column_name' => 'parts', 'column_name_alias' => 'parts', 'is_pk' => 0)); + break; + case 'polygonz': + array_push($columns, array('index' => $column_index, 'column_name' => 'parts', 'column_name_alias' => 'parts', 'is_pk' => 0)); + break; + case 'multipointz': + array_push($columns, array('index' => $column_index, 'column_name' => 'points', 'column_name_alias' => 'points', 'is_pk' => 0)); + break; } return $columns; @@ -296,7 +530,6 @@ public static function parseGeoProperty($options, $columns) $geo_properties = array(); if ($is_url) { - // This remains untested $tmp_file = uniqid(); file_put_contents($tmp_dir . '/' . $tmp_file . ".shp", file_get_contents(substr($options['uri'], 0, strlen($options['uri']) - 4) . ".shp")); @@ -317,7 +550,6 @@ public static function parseGeoProperty($options, $columns) } $shp_data = $record->getShpData(); - $shape_type = strtolower($record->getTypeLabel()); $geo_properties = array(); @@ -325,21 +557,51 @@ public static function parseGeoProperty($options, $columns) // Get the geographical column names // Either multiple coordinates will be set (identified by the parts) // or a lat long pair will be set (identified by x and y) - if (!empty($shp_data['parts'])) { - if ($shape_type === 'polyline') { + $shp_data = $record->getShpData(); + + $shape_type = self::$RECORD_TYPES[$record->getTypeCode()]; + + switch (strtolower($shape_type)) { + case 'point': + $x = $aliases['x']; + $y = $aliases['y']; + + array_push($geo_properties, array('property' => 'longitude', 'path' => $x)); + array_push($geo_properties, array('property' => 'latitude', 'path' => $y)); + break; + case 'pointz': + $x = $aliases['x']; + $y = $aliases['y']; + $z = $aliases['z']; + + array_push($geo_properties, array('property' => 'longitude', 'path' => $x)); + array_push($geo_properties, array('property' => 'latitude', 'path' => $y)); + array_push($geo_properties, array('property' => 'elevation', 'path' => $z)); + break; + case 'polyline': $parts = $aliases['parts']; array_push($geo_properties, array('property' => 'polyline', 'path' => $parts)); - } elseif ($shape_type === 'polygon') { + break; + case 'polylinez': + $parts = $aliases['parts']; + array_push($geo_properties, array('property' => 'polylinez', 'path' => $parts)); + break; + case 'polygon': $parts = $aliases['parts']; array_push($geo_properties, array('property' => 'polygon', 'path' => $parts)); - } else { // TODO support more types - \App::abort(400, 'Provided geometric type ($shape_type) is not supported'); - } - } elseif (isset($shp_data['x'])) { - $x = $aliases['x']; - $y = $aliases['y']; - array_push($geo_properties, array('property' => 'latitude', 'path' => $x)); - array_push($geo_properties, array('property' => 'longitude', 'path' => $y)); + break; + case 'polygonz': + $parts = $aliases['parts']; + array_push($geo_properties, array('property' => 'polygonz', 'path' => $parts)); + break; + case 'multipoint': + $parts = $aliases['points']; + array_push($geo_properties, array('property' => 'multipoint', 'path' => $parts)); + break; + case 'multipointz': + $parts = $aliases['points']; + array_push($geo_properties, array('property' => 'multipointz', 'path' => $parts)); + break; } return $geo_properties; diff --git a/app/Tdt/Core/DataControllers/SPARQLController.php b/app/Tdt/Core/DataControllers/SPARQLController.php index 0d20722e..a1015cde 100644 --- a/app/Tdt/Core/DataControllers/SPARQLController.php +++ b/app/Tdt/Core/DataControllers/SPARQLController.php @@ -37,7 +37,6 @@ public function readData($source_definition, $rest_parameters = array()) if (stripos($source_definition['query'], 'limit')) { $limitInQuery = true; } else { - list($limit, $offset) = Pager::calculateLimitAndOffset(); // Sparql endpoints often have a built in limit on the amount of rows that they return @@ -81,16 +80,14 @@ public function readData($source_definition, $rest_parameters = array()) $filter = ''; // Covers FROM <...> FROM <...> WHERE{ } , FROM <...> FROM <...> { }, WHERE { }, { } - $where_clause = '(.*?(FROM.+?{.+})|.*?(WHERE.*{.+})|.*?({.+}))[a-zA-Z0-9]*?'; + $where_clause = '(.+((FROM.*<.+>)+.*{.+})|.*?(WHERE.*{.+})|.*?({.+}))[a-zA-Z0-9]*?'; $matches = array(); if ($keyword == 'select') { - $regex = $keyword . $where_clause; preg_match_all("/(.*?)$regex/msi", $query, $matches); } else { - preg_match_all("/(.*?)$keyword(\s*\{[^{]+\})$where_clause/mis", $query, $matches); } @@ -102,11 +99,11 @@ public function readData($source_definition, $rest_parameters = array()) $filter = $matches[3][0]; } - if (!empty($matches[4][0])) { + if (!empty($matches[4][0]) && empty($filter)) { $filter = $matches[4][0]; } - if (!empty($matches[5][0])) { + if (!empty($matches[5][0]) && empty($filter)) { $filter = $matches[5][0]; } @@ -115,7 +112,6 @@ public function readData($source_definition, $rest_parameters = array()) } if (!$limitInQuery) { - // Prepare the query to count results $count_query = $matches[1][0] . ' SELECT (count(*) AS ?count) ' . $filter; @@ -159,7 +155,6 @@ public function readData($source_definition, $rest_parameters = array()) $q = str_replace("+", "%20", $q); if ($keyword == 'select') { - $query_uri = $endpoint . '?query=' . $q . '&format=' . urlencode("application/sparql-results+json"); $response = $this->executeUri($query_uri, $endpoint_user, $endpoint_password); @@ -172,7 +167,6 @@ public function readData($source_definition, $rest_parameters = array()) $is_semantic = false; } else { - $query_uri = $endpoint . '?query=' . $q . '&format=' . urlencode("application/rdf+xml"); $response = $this->executeUri($query_uri, $endpoint_user, $endpoint_password); @@ -188,19 +182,16 @@ public function readData($source_definition, $rest_parameters = array()) // Create the data object to return $data = new Data(); - $data->data = $result; if (!$limitInQuery) { $data->paging = $paging; } + $data->data = $result; $data->is_semantic = $is_semantic; $data->preferred_formats = $this->getPreferredFormats(); - \Log::info("SPARQL query: $query"); - if ($is_semantic) { - // Fetch the available namespaces and pass // them as a configuration of the semantic data result $ontologies = $this->ontologies->getAll(); @@ -223,7 +214,6 @@ public function readData($source_definition, $rest_parameters = array()) preg_match_all("/\\$\\{(.+?)\\}/", $source_definition['query'], $matches); if (!empty($matches[1])) { - $matches = $matches[1]; @@ -253,7 +243,6 @@ private function executeUri($uri, $user = '', $password = '') // If credentials are given, put the HTTP auth header in the cURL request if (!empty($user)) { - curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_USERPWD, $user . ":" . $password); } @@ -302,7 +291,6 @@ private function processParameters($query) preg_match_all("/\\$\\{(.+?)\\}/", $query, $placeholders, PREG_SET_ORDER); for ($i = 0; $i < count($placeholders); $i++) { - $placeholder = trim($placeholders[$i][1]); // Strip the array notation of the placeholder then keep its placeholders name @@ -323,12 +311,10 @@ private function processParameters($query) } if (empty($elements)) { - // ${name[0]} $index = strpos($placeholder, "["); if ($index !== false) { - $placeholder_name = substr($placeholder, 0, $index); $placeholder_index = substr($placeholder, $index + 1, -1); @@ -344,7 +330,6 @@ private function processParameters($query) } } } else { - if (!isset($parameters[$placeholder])) { $value = '?' . $placeholder; } else { @@ -386,7 +371,6 @@ private function processParameters($query) // Note that the logging of invalid parameters will happen twice, as we construct and execute // the count query as well as the given query foreach ($parameters as $key => $value) { - if (is_array($value)) { $log_value = implode(', ', $value); } else { @@ -410,7 +394,6 @@ private function processLogicalStatements($query) foreach ($elements as $element) { // Keyword is in the 3rd match if (array_key_exists($element[2], $parameters)) { - // Remove the templated piece, replace it with the value $query = str_replace($element[1], $element[3], $query); } else { @@ -421,10 +404,8 @@ private function processLogicalStatements($query) preg_match_all("/.*(ifnotset\((.*)\).*?\{(.*?)\}).*/m", $query, $elements, PREG_SET_ORDER); foreach ($elements as $element) { - // Keyword is in the 3rd match if (!array_key_exists($element[2], $parameters)) { - // Remove the templated piece, replace it with the value $query = str_replace($element[1], $element[3], $query); } else { @@ -442,7 +423,6 @@ private function processParameterFunction($values, $function, $pattern, $concat) switch ($function) { case "each": - if (!is_array($values)) { $values = array($values); } diff --git a/app/Tdt/Core/DataControllers/XLSController.php b/app/Tdt/Core/DataControllers/XLSController.php index 4db0d6e3..2f6cf9fd 100644 --- a/app/Tdt/Core/DataControllers/XLSController.php +++ b/app/Tdt/Core/DataControllers/XLSController.php @@ -55,19 +55,16 @@ public function readData($source_definition, $rest_parameters = array()) // Check if they match with the freshly parsed columns if (count($parsed_columns) != count($columns)) { - // Save the new config $this->tabular_columns->deleteBulk($source_definition['id'], 'XlsDefinition'); $this->tabular_columns->storeBulk($source_definition['id'], 'XlsDefinition', $columns); } else { foreach ($parsed_columns as $parsed_column) { - $column = array_shift($columns); foreach ($parsed_column as $key => $val) { if ($val != $column[$key]) { - // Save the new config $this->tabular_columns->deleteBulk($source_definition['id'], 'XlsDefinition'); $this->tabular_columns->storeBulk($source_definition['id'], 'XlsDefinition', $columns); @@ -90,7 +87,6 @@ public function readData($source_definition, $rest_parameters = array()) $pk = null; foreach ($columns as $column) { - if (!empty($column['is_pk'])) { $pk = $column['column_name_alias']; } @@ -107,9 +103,7 @@ public function readData($source_definition, $rest_parameters = array()) } try { - if (substr($uri, 0, 4) == "http") { - $tmpFile = uniqid(); file_put_contents($tmp_path . "/" . $tmpFile, file_get_contents($uri)); $php_obj = self::loadExcel($tmp_path . "/" . $tmpFile, $this->getFileExtension($uri), $sheet); @@ -137,18 +131,15 @@ public function readData($source_definition, $rest_parameters = array()) // Iterate all the rows of the Excell sheet foreach ($worksheet->getRowIterator() as $row) { - $row_index = $row->getRowIndex(); // If our offset is ok, start parsing the data from the excell sheet if ($row_index > $start_row) { - $cell_iterator = $row->getCellIterator(); $cell_iterator->setIterateOnlyExistingCells(false); // Only read rows that are allowed in the current requested page if ($offset <= $total_rows && $offset + $limit > $total_rows) { - $rowobject = new \stdClass(); // Iterate each cell in the row, create an array of the values with the name of the column @@ -170,17 +161,20 @@ public function readData($source_definition, $rest_parameters = array()) if (empty($row_objects[$rowobject->$pk])) { $row_objects[$rowobject->$pk] = $rowobject; } elseif (!empty($row_objects[$rowobject->$pk])) { - $double = $rowobject->$pk; \Log::info("The primary key $double has been used already for another record!"); } else { - $double = $rowobject->$pk; \Log::info("The primary key $double is empty."); } } } + $total_rows++; + + if ($total_rows >= 10000) { + break; + } } } @@ -237,7 +231,6 @@ private function createValues($columns, $data) $result = array(); foreach ($columns as $column) { - $value = @$data[$column['index']]; if (!is_null($value)) { @@ -245,7 +238,6 @@ private function createValues($columns, $data) } else { $index = $column['index']; - \Log::warning("The column $index contained an empty value in the XLS file."); $result[$column['column_name_alias']] = ''; } } @@ -273,7 +265,6 @@ public static function parseColumns($input) $tmp_dir = sys_get_temp_dir(); if (empty($columns)) { - if (!is_dir($tmp_dir)) { mkdir($tmp_dir); } @@ -282,7 +273,6 @@ public static function parseColumns($input) try { if ($is_uri) { - $tmp_file = uniqid(); file_put_contents($tmp_dir. "/" . $tmp_file, file_get_contents($input['uri'])); @@ -305,27 +295,22 @@ public static function parseColumns($input) } foreach ($worksheet->getRowIterator() as $row) { - $row_index = $row->getRowIndex(); // Rows start at 1 in XLS if ($row_index == $input['start_row'] + 1) { - $cell_iterator = $row->getCellIterator(); $cell_iterator->setIterateOnlyExistingCells(false); $column_index = 0; foreach ($cell_iterator as $cell) { - $column_name = ''; if ($cell->getValue() != "") { - $column_name = trim($cell->getCalculatedValue()); } else { - $column_name = 'column_' . $column_index; } diff --git a/app/Tdt/Core/DataControllers/XMLController.php b/app/Tdt/Core/DataControllers/XMLController.php index a66ff5a9..b8849fad 100644 --- a/app/Tdt/Core/DataControllers/XMLController.php +++ b/app/Tdt/Core/DataControllers/XMLController.php @@ -24,7 +24,6 @@ public static function getParameters() public function readData($source_definition, $rest_parameters = array()) { - $uri = $source_definition['uri']; // Keep track of the prefix URI's @@ -34,12 +33,10 @@ public function readData($source_definition, $rest_parameters = array()) if (Cache::has($uri)) { $data = Cache::get($uri); } else { - // Fetch the data $data =@ file_get_contents($uri); if (!empty($data)) { - $data = $this->XMLStringToArray($data); Cache::put($uri, $data, $source_definition['cache']); } else { $uri = $source_definition['uri']; @@ -52,170 +49,19 @@ public function readData($source_definition, $rest_parameters = array()) $data_result->semantic = $this->prefixes; $data_result->preferred_formats = $this->getPreferredFormats(); - return $data_result; - } - - /** - * Initialize recursion. - */ - private function XMLStringToArray($xmlstr) - { - $doc = new \DOMDocument(); - $doc->loadXML($xmlstr); - - return $this->convertDomNodeToArray($doc->documentElement); - } - - /** - * Get the full name of an element or attribute, namespace + name - * - * @param DOMElement $element (either DomAttr or DOMElement) - * @param boolean $isAttribute - * - * @return string - */ - private function getFullName($element, $isAttribute = false) - { - $prefix = $element->prefix; - - if (!empty($prefix)) { - - // Register the namespace and prefix - $this->prefixes[$prefix] = $element->namespaceURI; - - if ($isAttribute) { - - $attrName = $element->name; - - return $element->namespaceURI . $attrName; - } else { - - $tagName = $element->tagName; - - return str_replace($prefix . ':', $element->namespaceURI, $tagName); - } - } else { - if (!empty($element->tagName)) { - return $element->tagName; - } else { - return $element->name; - } - + if (!empty($source_definition['geo_formatted']) && $source_definition['geo_formatted']) { + $data_result->geo_formatted = true; } + + return $data_result; } /** - * Convert node to a PHP array. + * Provide an array a formatter priorities */ - private function convertDomNodeToArray($node) + protected function getPreferredFormats() { - $output = array(); - - switch ($node->nodeType) { - - case XML_CDATA_SECTION_NODE: - case XML_TEXT_NODE: - - $output = trim($node->textContent); - break; - - case XML_ELEMENT_NODE: - - // Check children - for ($i = 0; $i < $node->childNodes->length; $i++) { - - // Get child - $child = $node->childNodes->item($i); - - // Recursive fetch child XML - $value = $this->convertDomNodeToArray($child); - - // Check if child is a tag - if (isset($child->tagName)) { - - // Current tag - $tag = $this->getFullName($child); - - // Check if current tag is already defined - if (!isset($output[$tag])) { - - // If not, inititialize array - $output[$tag] = array(); - } - - // Push the child tag on the array - $output[$tag][] = $value; - - } elseif ($value) { - - // Child is plain text, preliminary solution - if (empty($output['@text'])) { - $output['@text'] = array(); - } - - array_push($output['@text'], (string) $value); - } - } - - // Element is not a text node - if (is_array($output)) { - - // Check if element has attributes - $attributesLength = $node->attributes->length; - - if ($attributesLength > 0) { - - $attributes = array(); - - for ($i = 0; $i < $attributesLength; $i++) { - - $attribute = $node->attributes->item($i); - - $attributeName = $this->getFullName($attribute, true); - $attributes[$attributeName] = (string) $attribute->value; - } - - if (!empty($attributes)) { - $output['@attributes'] = $attributes; - } - - } - // For each of the element's children - foreach ($output as $tag => $value) { - - if (is_array($value) && count($value) == 1 && $tag != '@attributes') { - $output[$tag] = @$value[0]; - } - } - } else { - // Element is a text node, but can still have attributes - $value = $output; - - // Check if element has attributes - $attributesLength = $node->attributes->length; - if ($attributesLength > 0) { - - $attributes = array(); - - for ($i = 0; $i < $attributesLength; $i++) { - - $attribute = $node->attributes->item($i); - - $attributeName = $this->getFullName($attribute, true); - $attributes[$attributeName] = (string) $attribute->value; - } - - if (!empty($attributes)) { - $output['@attributes'] = $attributes; - } - } - - array_push($output['@text'], $value); - - } - break; - } - - return $output; + // Both semantic and raw data structures support json + return array('xml'); } } diff --git a/app/Tdt/Core/Datasets/Data.php b/app/Tdt/Core/Datasets/Data.php index 71a27463..e4b62366 100644 --- a/app/Tdt/Core/Datasets/Data.php +++ b/app/Tdt/Core/Datasets/Data.php @@ -47,6 +47,11 @@ class Data */ public $geo; + /** + * Indicates the format is already in a geo compatible format (KML, GeoJSON, ...) + */ + public $geo_formatted; + /** * The raw data object (in PHP or an EasyRdf_Graph, the is_semantic property should be true if so) */ diff --git a/app/Tdt/Core/Datasets/DatasetController.php b/app/Tdt/Core/Datasets/DatasetController.php index 329a4e88..70d9c840 100644 --- a/app/Tdt/Core/Datasets/DatasetController.php +++ b/app/Tdt/Core/Datasets/DatasetController.php @@ -21,7 +21,6 @@ */ class DatasetController extends ApiController { - /** * Retrieve a Data object identified by $uri * @@ -44,23 +43,30 @@ public function get($uri) list($limit, $offset) = Pager::calculateLimitAndOffset(); $cache_string .= '/limit=' . $limit . 'offset=' . $offset; - $cache_string .= http_build_query(\Input::except('limit', 'offset', 'page', 'page_size')); + $omit = ['limit', 'offset', 'page', 'page_size']; + + $query_string_params = \Input::get(); + + foreach ($query_string_params as $key => $val) { + if (in_array($key, $omit)) { + unset($query_string_params[$key]); + } + } + + $cache_string .= http_build_query($query_string_params); $cache_string = sha1($cache_string); if (Cache::has($cache_string)) { return ContentNegotiator::getResponse(Cache::get($cache_string), $extension); } else { - // Get definition $definition = $this->definition->getByIdentifier($uri); if ($definition) { - // Get source definition $source_definition = $this->definition->getDefinitionSource($definition['source_id'], $definition['source_type']); if ($source_definition) { - $source_type = $source_definition['type']; // Create the right datacontroller @@ -73,9 +79,19 @@ public function get($uri) $rest_parameters = array_diff($uri_segments, array($definition['collection_uri'], $definition['resource_name'])); $rest_parameters = array_values($rest_parameters); + $throttle_response = $this->applyThrottle($definition); + if (!empty($throttle_response)) { + return $throttle_response; + } + // Retrieve dataobject from datacontroller $data = $data_controller->readData($source_definition, $rest_parameters); + // If the source type is XML, just return the XML contents, don't transform + if (strtolower($source_type) == 'xml' && $extension == 'xml') { + return $this->createXMLResponse($data->data); + } + $data->rest_parameters = $rest_parameters; // REST filtering @@ -83,6 +99,50 @@ public function get($uri) $data->data = self::applyRestFilter($data->data, $data->rest_parameters); } + // Semantic paging with the hydra voc + if ($data->is_semantic && !empty($data->paging)) { + \EasyRdf_Namespace::set('hydra', 'http://www.w3.org/ns/hydra/core#'); + $graph = $data->data; + $url = \URL::to($definition['collection_uri'] . '/' . $definition['resource_name']); + + $request_url = \Request::url(); + $graph->addResource($request_url, 'void:subset', $url); + + foreach ($data->paging as $key => $val) { + $paged_url = $request_url . '?offset=' . $val[0] . '&limit=' . $val[1] . Pager::buildQuerystring(); + + switch ($key) { + case 'next': + $graph->addResource($request_url, 'hydra:nextPage', $paged_url); + break; + case 'previous': + $graph->addResource($request_url, 'hydra:previousPage', $paged_url); + break; + case 'last': + $graph->addResource($request_url, 'hydra:lastPage', $paged_url); + break; + case 'first': + $graph->addResource($request_url, 'hydra:firstPage', $paged_url); + break; + } + } + + $graph->addResource($url, 'a', 'dcat:Dataset'); + + $title = null; + if (!empty($definition['title'])) { + $title = $definition['title']; + } else { + $title = $definition['collection_uri'] . '/' . $definition['resource_name']; + } + + $graph->addLiteral($url, 'dc:title', $title); + $graph->addLiteral($url, 'dc:description', $source_definition['description']); + $graph->addResource($url, 'dcat:distribution', $url . '.json'); + + $data->data = $graph; + } + // Add definition to the object $data->definition = $definition; @@ -103,19 +163,16 @@ public function get($uri) } } else { - // Coulnd't find a definition, but it might be a collection $resources = $this->definition->getByCollection($uri); if (count($resources) > 0) { - $data = new Data(); $data->data = new \stdClass(); $data->data->datasets = array(); $data->data->collections = array(); foreach ($resources as $res) { - // Check if it's a subcollection or a dataset $collection_uri = rtrim($res['collection_uri'], '/'); if ($collection_uri == $uri) { @@ -167,7 +224,6 @@ public function head($uri) $response = new \Response(); if ($definition) { - $response = \Response::make(null, 200); } else { @@ -202,14 +258,13 @@ private function processURI($uri) $formatter_class = 'Tdt\\Core\\Formatters\\' . $possible_extension . 'Formatter'; if (!class_exists($formatter_class)) { - // Re-attach the dot with the latter part of the uri - $uri .= '.' . $possible_extension; + $uri .= '.' . strtolower($possible_extension); return array($uri, null); } - return array($uri, $possible_extension); + return array($uri, strtolower($possible_extension)); } /** @@ -223,11 +278,9 @@ private function processURI($uri) private static function applyRestFilter($data, $rest_params) { foreach ($rest_params as $rest_param) { - if (is_object($data) && $key = self::propertyExists($data, $rest_param)) { $data = $data->$key; } elseif (is_array($data)) { - if ($key = self::keyExists($data, $rest_param)) { $data = $data[$key]; } elseif (is_numeric($rest_param)) { @@ -261,12 +314,10 @@ public static function fetchData($identifier) $definition = $definition_repo->getByIdentifier($identifier); if ($definition) { - // Get the source definition $source_definition = $definition_repo->getDefinitionSource($definition['source_id'], $definition['source_type']); if ($source_definition) { - // Create the correct datacontroller $controller_class = 'Tdt\\Core\\DataControllers\\' . $source_definition['type'] . 'Controller'; $data_controller = \App::make($controller_class); @@ -335,4 +386,51 @@ private static function keyExists($array, $property) } return false; } + + /** + * Return an XML response + * + * @return \Response + */ + public function createXMLResponse($data) + { + // Create response + $response = \Response::make($data, 200); + + // Set headers + return $response->header('Content-Type', 'text/xml;charset=UTF-8'); + } + + /** + * Throttle on the basis of source type + * + * @param array $definition + * + * @return Response + */ + private function applyThrottle($definition) + { + if ($definition['source_type'] == 'ElasticsearchDefinition') { + $requestsPerHour = 720; + + // Rate limit by IP address + $key = sprintf('api:%s', \Request::getClientIp()); + + // Add if doesn't exist + // Remember for 1 hour + \Cache::add($key, 0, 60); + + // Add to count + $count = \Cache::get($key); + + if ($count > $requestsPerHour) { + $response = \Response::make('', 429); + $response->setContent('Rate limit exceeded, maximum of ' . $requestsPerHour . ' requests per hour has been reached.'); + + return $response; + } else { + \Cache::increment($key); + } + } + } } diff --git a/app/Tdt/Core/Definitions/DcatController.php b/app/Tdt/Core/Definitions/DcatController.php index 172c9be8..7ee7bf31 100644 --- a/app/Tdt/Core/Definitions/DcatController.php +++ b/app/Tdt/Core/Definitions/DcatController.php @@ -57,7 +57,6 @@ public function get($uri) /** * Create the DCAT document of the published (non-draft) resources * - * @param $pieces array of uri pieces * @return mixed \Data object with a graph of DCAT information */ private function createDcat() @@ -68,6 +67,13 @@ private function createDcat() \EasyRdf_Namespace::set($prefix, $uri); } + // If limit is empty, provide a custom page size for the DCAT document + + $limit = \Input::get('limit'); + if (empty($limit)) { + \Input::merge(array('limit' => 100)); + } + // Apply paging when fetching the definitions list($limit, $offset) = Pager::calculateLimitAndOffset(); @@ -102,4 +108,16 @@ private function createDcat() return $data_result; } + + public function head($uri) + { + $response = \Response::make(null, 200); + + // Set headers + $response->header('Content-Type', 'text/turtle;charset=UTF-8'); + $response->header('Pragma', 'public'); + + // Return formatted response + return $response; + } } diff --git a/app/Tdt/Core/Definitions/GeoprojectionController.php b/app/Tdt/Core/Definitions/GeoprojectionController.php new file mode 100644 index 00000000..21ddeb61 --- /dev/null +++ b/app/Tdt/Core/Definitions/GeoprojectionController.php @@ -0,0 +1,72 @@ + + */ +class GeoprojectionController extends ApiController +{ + + private $geoprojections; + + public function __construct(GeoprojectionRepositoryInterface $geoprojections) + { + $this->geoprojections = $geoprojections; + } + + public function get($uri) + { + // Set permission + Auth::requirePermissions('info.view'); + + return $this->getProjections($uri); + } + + /** + * Return the headers of a call made to the uri given. + */ + public function head($uri) + { + $response = \Response::make(null, 200); + + // Set headers + $response->header('Content-Type', 'application/json;charset=UTF-8'); + $response->header('Pragma', 'public'); + + // Return formatted response + return $response; + } + + /* + * GET an info document based on the uri provided + */ + private function getProjections($uri) + { + return $this->makeResponse($this->geoprojections->getAll()); + } + + /** + * Return the response with the given data (formatted in json) + */ + private function makeResponse($data) + { + // Create response + $response = \Response::make(str_replace('\/', '/', json_encode($data))); + + // Set headers + $response->header('Content-Type', 'application/json;charset=UTF-8'); + + return $response; + } +} diff --git a/app/Tdt/Core/Definitions/SpectqlController.php b/app/Tdt/Core/Definitions/SpectqlController.php deleted file mode 100644 index c84b6666..00000000 --- a/app/Tdt/Core/Definitions/SpectqlController.php +++ /dev/null @@ -1,174 +0,0 @@ -performQuery($uri); - } - - /** - * Perform the SPECTQL query. - */ - private function performQuery($uri) - { - - SPECTQLController::$TMP_DIR = __DIR__ . "/../tmp/"; - - // Fetch the original uri, which is a hassle since our spectql format allows for a ? - character - // identify the start of a filter, the Request class sees this is the start of query string parameters - // and fails to parse them as they only contain keys, but never values ( our spectql filter syntax is nowhere near - // the same as a query string parameter sequence). Therefore, we need to build our spectql uri manually. - // Furthermore, after the ? - character dots are replaced with underscores by PHP itself. http://ca.php.net/variables.external - // This is another reason why we build the query string to be passed to the parser ourselves. - - // The Request class also seems to have an issue with evaluating a semi-colon in the query string - // It puts the semi-colon and what follows next to the first query string parameter, IF there are multiple - // query string parameters (lon>5&lon<10), since this isn't really supported by PHP, Request from Symfony tries - // apparently a best effort at fixing this. - - $filter = ""; - - $original_uri = \Request::fullUrl(); - $root = \Request::root(); - - if (preg_match("%$root\/spectql\/(.*)%", $original_uri, $matches)) { - $query_uri = urldecode($matches[1]); - } - - $format = ""; - - // Fetch the format of the query - if (preg_match("/.*(:[a-zA-Z]+)&?(.*?)/", $query_uri, $matches)) { - $format = ltrim($matches[1], ":"); - } - - // Remove the format and any following query string parameters - if (!empty($format)) { - $query_uri = preg_replace("/:" . $format . "\??.*/", '', $query_uri); - } - - // Initialize the parser with our query string - $parser = new SPECTQLParser($query_uri); - - $context = array(); // array of context variables - - $universalquery = $parser->interpret($context); - - // Display the query tree, uncomment in case of debugging - /*$treePrinter = new TreePrinter(); - $tree = $treePrinter->treeToString($universalquery); - echo "
";
-        echo $tree;
-        echo "
";*/ - - - $interpreter = new UniversalInterpreter(new UniversalFilterTableManager()); - $result = $interpreter->interpret($universalquery); - - // Convert the resulting table object to a php object - $converter = new TableToPhpObjectConverter(); - $object = $converter->getPhpObjectForTable($result); - - // Perform a clean-up, every property that is empty can be thrown away - foreach ($object as $index => $property) { - if ($this->isArrayNull($property)) { - unset($object[$index]); - } - } - - $rootname = "spectqlquery"; - - // Get the required properties for the Data object - $definition_uri = preg_match('/(.*?)\{.*/', $uri, $matches); - - // If no selection statement is given, abort the processing of the query - if (empty($matches)) { - \App::abort(400, "Please provide a select statement with the SPECTQL query (e.g. { column_1, column_2 })."); - } - - $definition_uri = $matches[1]; - - $definition_repo = \App::make('Tdt\\Core\\Repositories\\Interfaces\\DefinitionRepositoryInterface'); - $definition = $definition_repo->getByIdentifier($definition_uri); - - if (!empty($definition)) { - $source_definition = $definition_repo->getDefinitionSource($definition['source_id'], $definition['source_type']); - } - - $rest_parameters = str_replace($definition['collection_uri'] . '/' . $definition['resource_name'], '', $uri); - $rest_parameters = ltrim($rest_parameters, '/'); - $rest_parameters = explode('/', $rest_parameters); - - if (empty($rest_parameters[0]) && !is_numeric($rest_parameters[0])) { - $rest_parameters = array(); - } - - $data = new Data(); - $data->data = $object; - - // Specify it's a SPECTQL result - $data->is_spectql = true; - - $data->rest_parameters = $rest_parameters; - - // Add definition to the object - $data->definition = $definition; - - // Add source definition to the object - $data->source_definition = $source_definition; - - // Return the formatted response with content negotiation - return ContentNegotiator::getResponse($data, $format); - } - - /** - * Check if the property contains data - * - * - */ - private function isArrayNull($array) - { - - foreach ($array as $entry) { - if (!empty($entry)) { - return false; - } - } - - return true; - } -} diff --git a/app/Tdt/Core/Formatters/CSVFormatter.php b/app/Tdt/Core/Formatters/CSVFormatter.php index fcdcbf0c..783a07d3 100644 --- a/app/Tdt/Core/Formatters/CSVFormatter.php +++ b/app/Tdt/Core/Formatters/CSVFormatter.php @@ -25,7 +25,6 @@ public static function createResponse($dataObj) public static function getBody($dataObj) { - // Only tabular data is allowed if (!is_array($dataObj->data)) { \App::abort(400, "You can only request a CSV formatter on a tabular datastructure."); @@ -56,23 +55,10 @@ public static function getBody($dataObj) $i = 0; foreach ($row as $element) { - if (is_object($element)) { - if (isset($element->id)) { - $body .= $element->id; - } elseif (isset($element->name)) { - $body .= $element->name; - } else { - $body .= "n/a"; - } + \App::abort(400, "You can only request a CSV formatter on a tabular datastructure."); } elseif (is_array($element)) { - if (isset($element["id"])) { - $body .= $element["id"]; - } elseif (isset($element["name"])) { - $body .= $element["name"]; - } else { - $body .= "n/a"; - } + \App::abort(400, "You can only request a CSV formatter on a tabular datastructure."); } else { $body .= CSVFormatter::enclose($element); } diff --git a/app/Tdt/Core/Formatters/FormatHelper.php b/app/Tdt/Core/Formatters/FormatHelper.php index 9abbff9d..69df1fc5 100644 --- a/app/Tdt/Core/Formatters/FormatHelper.php +++ b/app/Tdt/Core/Formatters/FormatHelper.php @@ -11,7 +11,6 @@ */ class FormatHelper { - private static $tabular_sources = array('csv', 'xls', 'shp'); /** @@ -22,14 +21,19 @@ class FormatHelper */ public function getAvailableFormats($data) { - $formats = array( - 'JSON' => 'json', - 'XML' => 'xml', ); + $source_type = $data->source_definition['type']; + + if (strtolower($source_type) != 'xml') { + $formats['JSON'] = 'json'; + } else { + $formats['XML'] = 'xml'; + } + // Check for tabular sources - if (in_array(strtolower($data->source_definition['type']), self::$tabular_sources)) { + if (in_array(strtolower($source_type), self::$tabular_sources)) { $formats['CSV'] = 'csv'; } @@ -39,6 +43,14 @@ public function getAvailableFormats($data) $formats['KML'] = 'kml'; $formats['GeoJSON'] = 'geojson'; $formats['WKT'] = 'wkt'; + } elseif (!empty($data->geo_formatted) && $data->geo_formatted) { + if (strtolower($source_type) == 'xml') { + $formats['KML'] = 'kml'; + unset($formats['XML']); + } elseif (strtolower($source_type) == 'json' && $data->geo_formatted) { + $formats['GeoJSON'] = 'geojson'; + unset($formats['JSON']); + } } // Check for semantic sources, identified by the data being wrapped in an EasyRdf_Graph diff --git a/app/Tdt/Core/Formatters/GEOJSONFormatter.php b/app/Tdt/Core/Formatters/GEOJSONFormatter.php index 877c2b0c..67d72864 100644 --- a/app/Tdt/Core/Formatters/GEOJSONFormatter.php +++ b/app/Tdt/Core/Formatters/GEOJSONFormatter.php @@ -2,8 +2,11 @@ namespace Tdt\Core\Formatters; +use Tdt\Core\Formatters\XMLFormatter; +use Symm\Gisconverter\Gisconverter; + /** - * GEOJson Formatter + * GeoJSON Formatter * * @copyright (C) 2011, 2014 by OKFN Belgium vzw/asbl * @license AGPLv3 @@ -25,6 +28,11 @@ public static function createResponse($dataObj) public static function getBody($dataObj) { + // Check if the original data is not GeoJSON + if ($dataObj->source_definition['type'] == 'JSON' && !empty($dataObj->geo_formatted) && $dataObj->geo_formatted) { + return json_encode($dataObj->data); + } + // Build the body $body = $dataObj->data; if (is_object($body)) { @@ -32,6 +40,7 @@ public static function getBody($dataObj) } $features = array(); + foreach ($body as $dataRow) { if (is_object($dataRow)) { $dataRow = get_object_vars($dataRow); @@ -48,20 +57,22 @@ public static function getBody($dataObj) } } - $geomIDs_geom = self::findGeometry($geo, $dataRow); + $geometric_ids = self::findGeometry($geo, $dataRow); //Prevent geo information being duplicated in properties - foreach ($geomIDs_geom[0] as $geomID) { - unset($dataRow[$geomID]); + foreach ($geometric_ids[0] as $geometric_id) { + unset($dataRow[$geometric_id]); } $feature = array( 'type' => 'Feature', - 'geometry' => $geomIDs_geom[1], + 'geometry' => $geometric_ids[1], 'properties' => $dataRow ); - if (!empty($dataObj->definition['map_property']) && !empty($dataRow[$id_prop])) { + $id_prop = $dataObj->source_definition['map_property']; + + if (!empty($id_prop) && !empty($dataRow[$id_prop])) { $feature['id'] = $dataRow[$id_prop]; unset($dataRow[$id_prop]); } @@ -72,57 +83,187 @@ public static function getBody($dataObj) 'type' => 'FeatureCollection', 'features' => $features); + // Only add bounding box if we have features and are viewing the entire dataset. + if (!empty($features) && empty($dataObj->paging)) { + $result['bbox'] = self::boundingBox($features); + } + + return json_encode($result); } /** - * @param $geo array an array holding the identifier(s) for the geographical attribute - * @param $dataRow array an array holding attributes - * @return array an array containing the identifier(s) of the selected attribute and an + * @param array $geo an array holding the identifier(s) for the geographical attribute + * @param array $dataRow an array holding data + * @return array an array containing the identifier(s) of the selected attribute and an * object representing the extracted geometry */ public static function findGeometry($geo, $dataRow) { $geometry = null; $identifiers = array(); - if (!empty($geo['longitude']) && !empty($geo['latitude'])) { + + if (count($geo) == 2 && !empty($geo['longitude']) && !empty($geo['latitude'])) { array_push($identifiers, $geo['longitude']); array_push($identifiers, $geo['latitude']); $geometry = array( 'type' => 'Point', 'coordinates' => array( floatval($dataRow[$geo['longitude']]), - floatval($dataRow[$geo['latitude']]))); - } elseif (!empty($geo['point'])) { - array_push($identifiers, $geo['point']); - $coords = explode(',', $dataRow[$geo['point']]); - $geometry = array( - 'type' => 'Point', - 'coordinates' => array($coords[0], $coords[1]) - ); - } elseif (!empty($geo['multiline'])) { - array_push($identifiers, $geo['multiline']); - $coords = $dataRow[$geo['multiline']]; - $geometry = array( - 'type' => 'LineString', - 'coordinates' => self::convertCoordinateArray($coords) - ); - } elseif (!empty($geo['polyline'])) { - array_push($identifiers, $geo['polyline']); - $geometry = array( - 'type' => 'MultiLineString', - 'coordinates' => self::convertCoordinateMultiArray($dataRow[$geo['polyline']]) + floatval($dataRow[$geo['latitude']])) ); - } elseif (!empty($geo['polygon'])) { - array_push($identifiers, $geo['polygon']); + } elseif (count($geo) == 3 && !empty($geo['longitude']) && !empty($geo['latitude']) && !empty($geo['elevation'])) { + array_push($identifiers, $geo['longitude']); + array_push($identifiers, $geo['latitude']); + array_push($identifiers, $geo['elevation']); + $geometry = array( - 'type' => 'Polygon', - 'coordinates' => self::convertCoordinateMultiArray($dataRow[$geo['polygon']]) + 'type' => 'Point', + 'coordinates' => array( + floatval($dataRow[$geo['longitude']]), + floatval($dataRow[$geo['latitude']]), + floatval($dataRow[$geo['elevation']])) ); + } else { + $geo_type = key($geo); + + if (!empty($geo_type)) { + switch ($geo_type) { + case 'point': + array_push($identifiers, $geo['point']); + $coords = explode(',', $dataRow[$geo['point']]); + $geometry = array( + 'type' => 'Point', + 'coordinates' => array($coords[0], $coords[1]) + ); + break; + case 'polyline': + array_push($identifiers, $geo['polyline']); + $geometry = array( + 'type' => 'MultiLineString', + 'coordinates' => self::convertCoordinateMultiArray($dataRow[$geo['polyline']]) + ); + break; + case 'polygon': + array_push($identifiers, $geo['polygon']); + $geometry = array( + 'type' => 'Polygon', + 'coordinates' => self::convertCoordinateMultiArray($dataRow[$geo['polygon']]) + ); + break; + case 'multipoint': + array_push($identifiers, $geo['multipoint']); + $geometry = array( + 'type' => 'MultiPoint', + 'coordinates' => self::convertCoordinateSingleArray($dataRow[$geo['multipoint']]) + ); + break; + case 'pointz': + array_push($identifiers, $geo['pointz']); + $coords = explode(',', $dataRow[$geo['pointz']]); + $geometry = array( + 'type' => 'Point', + 'coordinates' => array($coords[0], $coords[1], $coords[2]) + ); + break; + case 'polylinez': + array_push($identifiers, $geo['polylinez']); + $geometry = array( + 'type' => 'MultiLineString', + 'coordinates' => self::convertCoordinateMultiArray($dataRow[$geo['polylinez']]) + ); + break; + case 'polygonz': + array_push($identifiers, $geo['polygonz']); + $geometry = array( + 'type' => 'Polygon', + 'coordinates' => self::convertCoordinateMultiArray($dataRow[$geo['polygonz']]) + ); + break; + case 'multipointz': + array_push($identifiers, $geo['multipoint']); + $geometry = array( + 'type' => 'MultiPoint', + 'coordinates' => self::convertCoordinateSingleArray($dataRow[$geo['multipointz']]) + ); + break; + } + } } + return array($identifiers, $geometry); } + /** + * Returns an array of n*2 numbers, where n is the maximum dimension of each + * coordinate present in the dataset. The first n numbers are the lower bounds of each + * dimension, the latter n numbers are the upper bounds of each dimension. + * @param $features array features for which to calculate the bounds + * @return array + */ + public static function boundingBox($features) + { + //The maximum dimensionality shared by all features (most likely 2 or 3). + // E.g.: Some features may be 2D, some may be 3D, in which case this value + // will be set to 2. + $max_dimension = 100; + $lowbounds = array(); + $topbounds = array(); + foreach ($features as $feature) { + if (empty($feature['geometry'])) { + // Geometry can be null. + continue; + } + + $coordinateList = array(); + self::toCoordinateList($feature['geometry']['coordinates'], $coordinateList); + + foreach ($coordinateList as $coordinate) { + $max_dimension = min($max_dimension, count($coordinate)); + for ($dim = 0; $dim < $max_dimension; $dim += 1) { + if (empty($lowbounds[$dim])) { + // First coordinate encountered + $lowbounds[$dim] = $coordinate[$dim]; + $topbounds[$dim] = $coordinate[$dim]; + } else { + $lowbounds[$dim] = min($lowbounds[$dim], $coordinate[$dim]); + $topbounds[$dim] = max($topbounds[$dim], $coordinate[$dim]); + } + } + } + } + return array_merge( + array_slice($lowbounds, 0, $max_dimension), + array_slice($topbounds, 0, $max_dimension) + ); + } + + /** + * Converts a coordinate array of a feature of any type to an array containing + * all used coordinates. Each coordinate is represented by an array of numbers, with one + * number for each dimension. + * @param $coordinates_array + * @param $out array eg for 2D data: ((1, 1), (2, 2), (3, 3)) + */ + public static function toCoordinateList($coordinates_array, &$out) + { + if (!empty($coordinates_array) && !is_array($coordinates_array[0])) { + array_push($out, $coordinates_array); + return; + } + + foreach ($coordinates_array as $array) { + if (empty($array)) { + continue; + } + if (is_array($array[0])) { + self::toCoordinateList($array, $out); + } else { + array_push($out, $array); + } + } + } + /** * @param $str string eg: "1.1,2.2 3.3,4.4" * @return array eg: ((1.1, 2.2), (3.3, 4.4)) @@ -130,9 +271,16 @@ public static function findGeometry($geo, $dataRow) public static function convertCoordinateArray($str) { $result = array(); - foreach (explode(' ', $str) as $coordinateStr) { - $coordinateStrArray = explode(',', $coordinateStr); - array_push($result, array(floatval($coordinateStrArray[0]), floatval($coordinateStrArray[1]))); + foreach (explode(' ', $str) as $coordinate_str) { + $coord_array = explode(',', $coordinate_str); + + if (count($coord_array) == 2) { + array_push($result, array(floatval($coord_array[0]), floatval($coord_array[1]))); + } elseif (count($coord_array) == 3) { + array_push($result, array(floatval($coord_array[0]), floatval($coord_array[1]), floatval($coord_array[2]))); + } else { + \Log::error("400", "An invalid coordinate was parsed."); + } } return $result; } @@ -144,8 +292,29 @@ public static function convertCoordinateArray($str) public static function convertCoordinateMultiArray($str) { $result = array(); - foreach (explode(';', $str) as $coordinateArrayStr) { - array_push($result, self::convertCoordinateArray($coordinateArrayStr)); + foreach (explode(';', $str) as $coord_str) { + array_push($result, self::convertCoordinateArray($coord_str)); + } + return $result; + } + + /** + * @param $str string eg: "1.1,2.2; 3.3,4.4; 5.5,6.6" + * @return array eg: ((1.1, 2.2), (3.3, 4.4), (5.5, 6.6), (7.7, 8.8)) + */ + public static function convertCoordinateSingleArray($str) + { + $result = array(); + foreach (explode(';', $str) as $coord_str) { + $coordinates_array = explode(',', $coord_str); + + if (count($coordinates_array) == 2) { + array_push($result, array(floatval($coordinates_array[0]), floatval($coordinates_array[1]))); + } elseif (count($coordinates_array) == 3) { + array_push($result, array(floatval($coordinates_array[0]), floatval($coordinates_array[1]), floatval($coordinates_array[2]))); + } else { + \Log::error("400", "An invalid coordinate was parsed."); + } } return $result; } @@ -154,4 +323,4 @@ public static function getDocumentation() { return "Returns a GeoJSON document."; } -} \ No newline at end of file +} diff --git a/app/Tdt/Core/Formatters/GeoHelper.php b/app/Tdt/Core/Formatters/GeoHelper.php index 81c1b8c2..6610e9cb 100644 --- a/app/Tdt/Core/Formatters/GeoHelper.php +++ b/app/Tdt/Core/Formatters/GeoHelper.php @@ -1,4 +1,7 @@ paging)) { $input_array = array_except(\Input::all(), array('limit', 'offset')); + + $query_string = ''; + if (!empty($input_array)) { + $query_string = '&' . http_build_query($input_array); + } + if (!empty($dataObj->paging['previous'])) { - $prev_link = '?' . http_build_query($input_array) . '&offset=' . $dataObj->paging['previous'][0] . '&limit=' . $dataObj->paging['previous'][1]; + $prev_link = '?offset=' . $dataObj->paging['previous'][0] . '&limit=' . $dataObj->paging['previous'][1] . $query_string; } if (!empty($dataObj->paging['next'])) { - $next_link = '?' . http_build_query($input_array) . '&offset=' . $dataObj->paging['next'][0] . '&limit=' . $dataObj->paging['next'][1]; + $next_link = '?offset=' . $dataObj->paging['next'][0] . '&limit=' . $dataObj->paging['next'][1] . $query_string; } } - if ($dataObj->is_spectql) { - // Create the link to the dataset - $dataset_link = \URL::to('spectql/' . $dataObj->definition['collection_uri'] . "/" . $dataObj->definition['resource_name']); + // Create the link to the dataset + $dataset_link = \URL::to($dataObj->definition['collection_uri'] . "/" . $dataObj->definition['resource_name']); - // Append rest parameters - if (!empty($dataObj->rest_parameters)) { - $dataset_link .= implode('/', $dataObj->rest_parameters); - $dataset_link = substr($dataset_link, 0, -5); - } + // Append rest parameters + if (!empty($dataObj->rest_parameters)) { + $dataset_link .= '/' . implode('/', $dataObj->rest_parameters); + } - $view = 'dataset.spectql'; - $data = self::displayTree($dataObj->data); + if (!empty($dataObj->source_definition)) { + $type = $dataObj->source_definition['type']; - } else { + // Check if other views need to be served + switch ($type) { + case 'XLS': + case 'CSV': + $first_row = array_shift($dataObj->data); + array_unshift($dataObj->data, $first_row); - // Create the link to the dataset - $dataset_link = \URL::to($dataObj->definition['collection_uri'] . "/" . $dataObj->definition['resource_name']); + if (is_array($first_row) || is_object($first_row)) { + $view = 'dataset.tabular'; + $data = $dataObj->data; - // Append rest parameters - if (!empty($dataObj->rest_parameters)) { - $dataset_link .= '/' . implode('/', $dataObj->rest_parameters); - } + } else { + $view = 'dataset.code'; + $data = self::displayTree($dataObj->data); - if (!empty($dataObj->source_definition)) { + } - $type = $dataObj->source_definition['type']; + break; + case 'SHP': + $view = 'dataset.map'; + $data = $dataset_link . '.map' . $query_string; - // Check if other views need to be served - switch($type){ - case 'XLS': - case 'CSV': + break; - $first_row = array_shift($dataObj->data); - array_unshift($dataObj->data, $first_row); + case 'XML': + $view = 'dataset.code'; + $data = self::displayTree($dataObj->data, 'xml'); + break; - if (is_array($first_row) || is_object($first_row)) { + default: + if ($dataObj->is_semantic) { + // This data object is always semantic + $view = 'dataset.turtle'; - $view = 'dataset.tabular'; - $data = $dataObj->data; + // Check if a configuration is given + $conf = array(); - } else { + if (!empty($dataObj->semantic->conf)) { + $conf = $dataObj->semantic->conf; + } - $view = 'dataset.code'; - $data = $data = self::displayTree($dataObj->data); + $data = $dataObj->data->serialise('turtle'); + } else { + $view = 'dataset.code'; + $data = self::displayTree($dataObj->data); + } - } + break; + } - break; - case 'SHP': - $view = 'dataset.map'; - $data = $dataset_link . '.map' . $query_string; + } elseif ($dataObj->is_semantic) { + // The data object can be semantic without a specified source type + $view = 'dataset.code'; + $data = $dataObj->data->serialise('turtle'); - break; + } else { + // Collection view + $view = 'dataset.collection'; + $data = $dataObj->data; + } - default: - if ($dataObj->is_semantic) { - // This data object is always semantic - $view = 'dataset.turtle'; + // Gather meta-data to inject as a JSON-LD document so it can be picked up by search engines + $definition = $dataObj->definition; - // Check if a configuration is given - $conf = array(); + $uri = \Request::root(); + $graph = new \EasyRdf_Graph(); - if (!empty($dataObj->semantic->conf)) { - $conf = $dataObj->semantic->conf; - } + // Create the dataset uri + $dataset_uri = $uri . "/" . $definition['collection_uri'] . "/" . $definition['resource_name']; + $dataset_uri = str_replace(' ', '%20', $dataset_uri); - $data = $dataObj->data->serialise('turtle'); - } else { + // Add the dataset resource and its description + $graph->addResource($dataset_uri, 'a', 'schema:Dataset'); - $view = 'dataset.code'; - $data = self::displayTree($dataObj->data); + // Add the title to the dataset resource of the catalog + if (!empty($definition['title'])) { + $graph->addLiteral($dataset_uri, 'schema:headline', $definition['title']); + } - } + // Add the description, identifier, issues, modified of the dataset + $graph->addLiteral($dataset_uri, 'schema:description', @$definition['description']); + $graph->addLiteral($dataset_uri, 'schema:dateCreated', date(\DateTime::ISO8601, strtotime($definition['created_at']))); + $graph->addLiteral($dataset_uri, 'schema:dateModified', date(\DateTime::ISO8601, strtotime($definition['updated_at']))); - break; + // Add the publisher resource to the dataset + if (!empty($definition['publisher_name']) && !empty($definition['publisher_uri'])) { + $graph->addResource($dataset_uri, 'schema:publisher', $definition['publisher_uri']); + } + + // Optional dct terms + $optional = array('date', 'language'); + $languages = \App::make('Tdt\Core\Repositories\Interfaces\LanguageRepositoryInterface'); + $licenses = \App::make('Tdt\Core\Repositories\Interfaces\LicenseRepositoryInterface'); + + foreach ($optional as $dc_term) { + if (!empty($definition[$dc_term])) { + if ($dc_term == 'language') { + $lang = $languages->getByName($definition[$dc_term]); + + if (!empty($lang)) { + $graph->addResource($dataset_uri, 'schema:inLanguage', 'http://lexvo.org/id/iso639-3/' . $lang['lang_id']); + } + } else { + $graph->addLiteral($dataset_uri, 'schema:datasetTimeInterval', $definition[$dc_term]); } + } + } - } else if ($dataObj->is_semantic) { + // Add the distribution of the dataset for SEO + $format = '.json'; - // The data object can be semantic without a specified source type - $view = 'dataset.code'; - $data = $dataObj->data->serialise('turtle'); + if ($definition['source_type'] == 'ShpDefinition') { + $format = '.geojson'; + } - } else { - // Collection view - $view = 'dataset.collection'; - $data = $dataObj->data; + $dataDownload = $graph->newBNode(); + + $graph->addResource($dataset_uri, 'schema:distribution', $dataDownload); + $graph->addResource($dataDownload, 'a', 'schema:DataDownload'); + $graph->addResource($dataDownload, 'schema:contentUrl', $dataset_uri . $format); + + // Add the license to the distribution + if (!empty($definition['rights'])) { + $license = $licenses->getByTitle($definition['rights']); + + if (!empty($license) && !empty($license['url'])) { + $graph->addResource($dataset_uri, 'schema:license', $license['url']); + } + + if (!empty($license)) { + $dataObj->definition['rights_uri'] = $license['url']; } } + $jsonld = $graph->serialise('jsonld'); + // Render the view return \View::make($view)->with('title', 'Dataset: '. $dataObj->definition['collection_uri'] . "/" . $dataObj->definition['resource_name'] . ' | The Datatank') - ->with('body', $data) - ->with('page_title', $dataObj->definition['collection_uri'] . "/" . $dataObj->definition['resource_name']) - ->with('definition', $dataObj->definition) - ->with('paging', $dataObj->paging) - ->with('source_definition', $dataObj->source_definition) - ->with('formats', $dataObj->formats) - ->with('dataset_link', $dataset_link) - ->with('prev_link', $prev_link) - ->with('next_link', $next_link) - ->with('query_string', $query_string); + ->with('body', $data) + ->with('page_title', $dataObj->definition['collection_uri'] . "/" . $dataObj->definition['resource_name']) + ->with('definition', $dataObj->definition) + ->with('paging', $dataObj->paging) + ->with('source_definition', $dataObj->source_definition) + ->with('formats', $dataObj->formats) + ->with('dataset_link', $dataset_link) + ->with('prev_link', $prev_link) + ->with('next_link', $next_link) + ->with('query_string', $query_string) + ->with('json_ld', $jsonld); } public static function getDocumentation() @@ -157,19 +222,64 @@ public static function getDocumentation() return "The HTML formatter is a formatter which prints output for humans. It prints everything in the internal object and extra links towards meta-data and documentation."; } - private static function displayTree($data) + private static function displayTree($data, $format = 'json') { + if ($format == 'json') { + if (is_object($data)) { + $data = get_object_vars($data); + } - if (is_object($data)) { - $data = get_object_vars($data); - } + if (defined('JSON_PRETTY_PRINT')) { + $formattedJSON = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + } else { + $formattedJSON = json_encode($data); + } - if (defined('JSON_PRETTY_PRINT')) { - $formattedJSON = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + return str_replace("\/", "/", $formattedJSON); + } elseif ($format == 'xml') { + return self::xmlPrettify($data, true); } else { - $formattedJSON = json_encode($data); + \App::abort('400', "The requested format ($format) is not supported."); } + } - return str_replace("\/", "/", $formattedJSON); + /** + * Prettifies an XML string into a human-readable form + * + * @param string $xml The XML as a string + * @param boolean $html_output True if the output should be escaped (for use in HTML) + * + * @return string + */ + private static function xmlPrettify($xml) + { + $xml_obj = new \SimpleXMLElement($xml); + $level = 4; + $level = 4; + $indent = 0; + $pretty = array(); + + $xml = explode("\n", preg_replace('/>\s*\n<", $xml_obj->asXML())); + + if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) { + $pretty[] = array_shift($xml); + } + + foreach ($xml as $el) { + if (preg_match('/^<([\w])+[^>\/]*>$/U', $el)) { + $pretty[] = str_repeat(' ', $indent) . $el; + $indent += $level; + } else { + if (preg_match('/^<\/.+>$/', $el)) { + $indent -= $level; + } + if ($indent < 0) { + $indent += $level; + } + $pretty[] = str_repeat(' ', $indent) . $el; + } + } + $xml = implode("\n", $pretty); + return htmlentities($xml); } } diff --git a/app/Tdt/Core/Formatters/KMLFormatter.php b/app/Tdt/Core/Formatters/KMLFormatter.php index 1ad1b786..dd606efb 100644 --- a/app/Tdt/Core/Formatters/KMLFormatter.php +++ b/app/Tdt/Core/Formatters/KMLFormatter.php @@ -2,6 +2,8 @@ namespace Tdt\Core\Formatters; +use Tdt\Core\Formatters\XMLFormatter; + /** * KML Formatter * @@ -29,8 +31,13 @@ public static function createResponse($dataObj) public static function getBody($dataObj) { + // Check if the original data is not GeoJSON + if ($dataObj->source_definition['type'] == 'XML' && !empty($dataObj->geo_formatted) && $dataObj->geo_formatted) { + return $dataObj->data; + } + self::$definition = $dataObj->definition; - self::$map_property = $dataObj->definition['map_property']; + self::$map_property = $dataObj->source_definition['map_property']; // Build the body // KML header @@ -67,9 +74,20 @@ private static function xmlgetelement($value) return $result; } - private static function getExtendedDataElement($value) + private static function getExtendedDataElement($values) { $result = ""; + $ignore = ['parts', 'points', 'point']; + + foreach ($values as $key => $val) { + if (!in_array($key, $ignore)) { + $result .= ''; + $result .= '' . $key . ''; + $result .= '' . $val . ''; + $result .= ''; + } + } + $result .= ""; return $result; } @@ -94,9 +112,6 @@ private static function printArray($val) } if ($lat_long) { - unset($array[$lat_long[0]]); - unset($array[$lat_long[1]]); - $name = self::xmlgetelement($array); $extendeddata = self::getExtendedDataElement($array); } elseif ($coordskey) { @@ -135,15 +150,37 @@ private static function printArray($val) // For data read from XML latitude and longitude will be an array of @value = 3.342... $lat_val = $array[$lat_long[0]]; $lon_val = $array[$lat_long[1]]; - if (is_array($lat_val)) { - $lat_val = reset($lat); - } - if (is_array($lon_val)) { - $lon_val = reset($lon_val); - } - if ($lat_val != 0 || $lon_val != 0) { - echo "" . $lon_val . "," . $lat_val . ""; + if (!empty($lat_long[2]) && !empty($array[$lat_long[2]])) { + $z_val = $array[$lat_long[2]]; + + if (is_array($lat_val)) { + $lat_val = reset($lat); + } + + if (is_array($lon_val)) { + $lon_val = reset($lon_val); + } + + if (is_array($z_val)) { + $z_val = reset($z_val); + } + + if ($lat_val != 0 || $lon_val != 0) { + echo "" . $lon_val . "," . $lat_val . "," . $z_val . ""; + } + } else { + if (is_array($lat_val)) { + $lat_val = reset($lat); + } + + if (is_array($lon_val)) { + $lon_val = reset($lon_val); + } + + if ($lat_val != 0 || $lon_val != 0) { + echo "" . $lon_val . "," . $lat_val . ""; + } } } @@ -202,8 +239,8 @@ private static function getArray($dataObj, $geo) $name = $entry['name']; } - if (!empty($dataObj->map_property) && !empty($entry[$dataObj->map_property])) { - $name = $entry[$dataObj->map_property]; + if (!empty(self::$map_property) && !empty($entry[self::$map_property])) { + $name = $entry[self::$map_property]; } $extendeddata = self::getExtendedDataElement($entry); @@ -218,25 +255,56 @@ private static function getArray($dataObj, $geo) $body .= $extendeddata; if ($is_point) { - if (count($geo) > 1) { + if (count($geo) == 2) { $point = $entry[$geo['longitude']] . ',' . $entry[$geo['latitude']]; + } elseif (count($geo) == 3) { + $point = $entry[$geo['longitude']] . ',' . $entry[$geo['latitude']] . ',' . $entry[$geo['elevation']]; } else { $point = $entry[$geo['point']]; } $body .= "" . $point . ""; } else { - if ($geo_type == 'polyline') { - $body .= ""; - foreach (explode(';', $entry[$geo['polyline']]) as $coord) { - $body .= "".$coord.""; - } - $body .= ""; + switch ($geo_type) { + case 'polylinez': + $body .= ""; - } elseif ($geo_type == 'polygon') { - $body .= "". $entry[$geo['polygon']] .""; - } else { - \App::abort(500, "The geo type, $geo_type, is not supported. Make sure the (combined) geo type is correct. (e.g. latitude and longitude are given)."); + foreach (explode(';', $entry[$geo['polylinez']]) as $coord) { + $body .= "" . $coord . ""; + } + $body .= ""; + break; + case 'polyline': + $body .= ""; + + foreach (explode(';', $entry[$geo['polyline']]) as $coord) { + $body .= "" . $coord . ""; + } + $body .= ""; + break; + case 'polygonz': + $body .= "". $entry[$geo['polygonz']] . ""; + break; + case 'polygon': + $body .= "". $entry[$geo['polygon']] . ""; + break; + case 'multipoinz': + $body .= ""; + foreach (explode(';', $entry[$geo['multipointz']]) as $point) { + $body .= '' . $point . ''; + } + $body .= ''; + break; + case 'multipoint': + $body .= ""; + foreach (explode(';', $entry[$geo['multipoint']]) as $point) { + $body .= '' . $point . ''; + } + $body .= ''; + break; + default: + \App::abort(500, "The geo type, $geo_type, is not supported. Make sure the (combined) geo type is correct. (e.g. latitude and longitude are given)."); + break; } } $body .= ""; diff --git a/app/Tdt/Core/Formatters/MAPFormatter.php b/app/Tdt/Core/Formatters/MAPFormatter.php index b7d9d644..da8c9a22 100644 --- a/app/Tdt/Core/Formatters/MAPFormatter.php +++ b/app/Tdt/Core/Formatters/MAPFormatter.php @@ -3,6 +3,7 @@ namespace Tdt\Core\Formatters; use Request; + /** * Map Formatter * @@ -28,11 +29,7 @@ public static function createResponse($dataObj) public static function getBody($dataObj) { $url = Request::url(); - $url = preg_replace('/\.([^\.]*)$/m', '.kml', $url); - - if (substr($url, -4) != '.kml'){ - $url .= '.kml'; - } + $url = preg_replace('/\.([^\.]*)$/m', '.geojson', $url); $resource = $dataObj->definition['collection_uri'] . "/" . $dataObj->definition['resource_name']; diff --git a/app/Tdt/Core/Formatters/WKTFormatter.php b/app/Tdt/Core/Formatters/WKTFormatter.php index bbee164f..b1b53d89 100644 --- a/app/Tdt/Core/Formatters/WKTFormatter.php +++ b/app/Tdt/Core/Formatters/WKTFormatter.php @@ -32,7 +32,6 @@ public static function createResponse($dataObj) public static function getBody($dataObj) { - // Get the KML and transform it to GeoJSON $kml = KMLFormatter::getBody($dataObj); return Gisconverter::kmlToWkt($kml); diff --git a/app/Tdt/Core/HomeController.php b/app/Tdt/Core/HomeController.php index 4ca7efa4..64e544a2 100644 --- a/app/Tdt/Core/HomeController.php +++ b/app/Tdt/Core/HomeController.php @@ -4,6 +4,7 @@ /** * HomeController + * * @copyright (C) 2011, 2014 by OKFN Belgium vzw/asbl * @license AGPLv3 * @author Michiel Vancoillie diff --git a/app/Tdt/Core/Pager.php b/app/Tdt/Core/Pager.php index 90ad8e0c..7aea065c 100644 --- a/app/Tdt/Core/Pager.php +++ b/app/Tdt/Core/Pager.php @@ -12,7 +12,12 @@ */ class Pager { - protected static $PAGING_KEYWORDS = array('next', 'last', 'previous', 'first'); + protected static $PAGING_KEYWORDS = array( + 'next' => 'http://www.w3.org/ns/hydra/core#nextPage', + 'last' => 'http://www.w3.org/ns/hydra/core#lastPage', + 'previous' => 'http://www.w3.org/ns/hydra/core#previousPage', + 'first' => 'http://www.w3.org/ns/hydra/core#firstPage' + ); protected static $DEFAULT_PAGE_SIZE = 500; @@ -24,10 +29,8 @@ protected static function getLinkHeader($paging) $link_value = ''; foreach ($paging as $keyword => $page_info) { - - if (!in_array($keyword, self::$PAGING_KEYWORDS)) { - - $key_words = implode(', ', self::$PAGING_KEYWORDS); + if (!in_array($keyword, array_keys(self::$PAGING_KEYWORDS))) { + $key_words = implode(', ', array_keys(self::$PAGING_KEYWORDS)); \App::abort(400, "The given paging keyword, $keyword, has not been found. Supported keywords are $key_words."); } elseif (count($page_info) != 2) { @@ -36,7 +39,7 @@ protected static function getLinkHeader($paging) $request_string = self::buildQuerystring(); - $link_value .= \Request::url() . '?offset=' . $page_info[0] . '&limit=' . $page_info[1] . $request_string .';rel=' . $keyword . ','; + $link_value .= \Request::url() . '?offset=' . $page_info[0] . '&limit=' . $page_info[1] . $request_string .';rel=' . self::$PAGING_KEYWORDS[$keyword] . ','; } // Trim the most right comma off. @@ -50,7 +53,7 @@ protected static function getLinkHeader($paging) * * @return string */ - private static function buildQuerystring() + public static function buildQuerystring() { $request_params = \Request::all(); $request_params = array_except($request_params, array('limit', 'offset')); @@ -84,7 +87,6 @@ public static function calculatePagingHeaders($limit, $offset, $total_rows) // Calculate the paging parameters and pass them with the data object if ($offset + $limit < $total_rows) { - $paging['next'] = array($limit + $offset, $limit); $last_page = round($total_rows / $limit, 1); @@ -120,17 +122,14 @@ public static function calculateLimitAndOffset() // Calculate the limit and offset, if only page and optionally page_size are given if ($limit == self::$DEFAULT_PAGE_SIZE && $offset == 0) { - $page = \Input::get('page', 1); $page_size = \Input::get('page_size', self::$DEFAULT_PAGE_SIZE); // Don't do extra work when page and page_size are also default values if ($page > 1 || $page_size != self::$DEFAULT_PAGE_SIZE) { - $offset = ($page -1)*$page_size; $limit = $page_size; } elseif ($page == -1) { - $limit = PHP_INT_MAX; $offset= 0; } diff --git a/app/Tdt/Core/Repositories/BaseDefinitionRepository.php b/app/Tdt/Core/Repositories/BaseDefinitionRepository.php index aeb050bc..9c7bbf63 100644 --- a/app/Tdt/Core/Repositories/BaseDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/BaseDefinitionRepository.php @@ -93,11 +93,12 @@ public function update($model_id, array $input) protected function processInput(array $input) { foreach ($this->getCreateParameters() as $key => $info) { - if (empty($input[$key]) && (!empty($info['default_value']) || !is_null(@$info['default_value']))) { $input[$key] = @$info['default_value']; } elseif (empty($input[$key])) { $input[$key] = null; + } else { + $input[$key] = trim($input[$key]); } } @@ -108,7 +109,8 @@ protected function processInput(array $input) * Patch the input given with the existing properties of a model and return the resulting array * * @param integer $id - * @param array $input + * @param array $input + * * @return array model */ protected function patchInput($model_id, array $input) @@ -116,7 +118,6 @@ protected function patchInput($model_id, array $input) $model = $this->getById($model_id); foreach ($model as $property => $value) { - if (empty($input[$property]) && !is_numeric(@$input[$property])) { $input[$property] = $model[$property]; } diff --git a/app/Tdt/Core/Repositories/CsvDefinitionRepository.php b/app/Tdt/Core/Repositories/CsvDefinitionRepository.php index 223e454b..a0c41a34 100644 --- a/app/Tdt/Core/Repositories/CsvDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/CsvDefinitionRepository.php @@ -74,7 +74,7 @@ public function getCreateParameters() 'required' => true, 'name' => 'Description', 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', + 'type' => 'text', ), 'delimiter' => array( 'required' => false, @@ -87,7 +87,7 @@ public function getCreateParameters() 'required' => false, 'name' => 'Header row', 'description' => 'Boolean parameter defining if the separated value file contains a header row that contains the column names.', - 'default_value' => 1, + 'default_value' => true, 'type' => 'boolean', ), 'start_row' => array( @@ -104,7 +104,7 @@ public function getCreateParameters() The value must be the index of the column you want each row to be mapped on. The pk property will never explicitly appear in the definition, but will manifest itself as part of a column property.', 'type' => 'integer', - ), + ) ); } } diff --git a/app/Tdt/Core/Repositories/DbServiceProvider.php b/app/Tdt/Core/Repositories/DbServiceProvider.php index de7fd662..215e52c5 100644 --- a/app/Tdt/Core/Repositories/DbServiceProvider.php +++ b/app/Tdt/Core/Repositories/DbServiceProvider.php @@ -105,5 +105,20 @@ public function register() 'Tdt\Core\Repositories\Interfaces\MysqlDefinitionRepositoryInterface', 'Tdt\Core\Repositories\MysqlDefinitionRepository' ); + + \App::bind( + 'Tdt\Core\Repositories\Interfaces\MongoDefinitionRepositoryInterface', + 'Tdt\Core\Repositories\MongoDefinitionRepository' + ); + + \App::bind( + 'Tdt\Core\Repositories\Interfaces\ElasticsearchDefinitionRepositoryInterface', + 'Tdt\Core\Repositories\ElasticsearchDefinitionRepository' + ); + + \App::bind( + 'Tdt\Core\Repositories\Interfaces\GeoprojectionRepositoryInterface', + 'Tdt\Core\Repositories\GeoprojectionRepository' + ); } } diff --git a/app/Tdt/Core/Repositories/DcatRepository.php b/app/Tdt/Core/Repositories/DcatRepository.php index f5657ff5..fbf4acaf 100644 --- a/app/Tdt/Core/Repositories/DcatRepository.php +++ b/app/Tdt/Core/Repositories/DcatRepository.php @@ -11,9 +11,9 @@ class DcatRepository implements DcatRepositoryInterface { + private $GEO_TYPES = ['ShpDefinition']; - public function __construct - ( + public function __construct( LicenseRepositoryInterface $licenses, LanguageRepositoryInterface $languages, SettingsRepositoryInterface $settings, @@ -37,6 +37,8 @@ public function getDcatDocument(array $definitions, $oldest_definition) // Create a new EasyRDF graph $graph = new \EasyRdf_Graph(); + \EasyRdf_Namespace::set('adms', 'http://www.w3.org/ns/adms#'); + $all_settings = $this->settings->getAll(); $uri = \Request::root(); @@ -68,12 +70,10 @@ public function getDcatDocument(array $definitions, $oldest_definition) $graph->addLiteral($all_settings['catalog_publisher_uri'], 'foaf:name', $all_settings['catalog_publisher_name']); if (count($definitions) > 0) { - // Add the last modified timestamp in ISO8601 $graph->addLiteral($uri . '/api/dcat', 'dct:modified', date(\DateTime::ISO8601, strtotime($oldest_definition['updated_at']))); foreach ($definitions as $definition) { - // Create the dataset uri $dataset_uri = $uri . "/" . $definition['collection_uri'] . "/" . $definition['resource_name']; $dataset_uri = str_replace(' ', '%20', $dataset_uri); @@ -86,22 +86,30 @@ public function getDcatDocument(array $definitions, $oldest_definition) // Add the dataset resource and its description $graph->addResource($dataset_uri, 'a', 'dcat:Dataset'); - // Add the title to the dataset resource of the catalog + $title = null; if (!empty($definition['title'])) { - $graph->addLiteral($dataset_uri, 'dct:title', $definition['title']); + $title = $definition['title']; } else { - $graph->addLiteral($dataset_uri, 'dct:title', $definition['collection_uri'] . '/' . $definition['resource_name']); + $title = $definition['collection_uri'] . '/' . $definition['resource_name']; } - // Add the description, identifier, issues, modified of the dataset + $graph->addLiteral($dataset_uri, 'dct:title', $title); + + + // Add the description, identifier, issued date, modified date, contact point and landing page of the dataset $graph->addLiteral($dataset_uri, 'dct:description', @$definition['description']); $graph->addLiteral($dataset_uri, 'dct:identifier', str_replace(' ', '%20', $definition['collection_uri'] . '/' . $definition['resource_name'])); $graph->addLiteral($dataset_uri, 'dct:issued', date(\DateTime::ISO8601, strtotime($definition['created_at']))); $graph->addLiteral($dataset_uri, 'dct:modified', date(\DateTime::ISO8601, strtotime($definition['updated_at']))); + $graph->addResource($dataset_uri, 'dcat:landingPage', $dataset_uri); + + // Backwards compatibility + if (!empty($definition['contact_point'])) { + $graph->addResource($dataset_uri, 'adms:contactPoint', $definition['contact_point']); + } // Add the publisher resource to the dataset if (!empty($definition['publisher_name']) && !empty($definition['publisher_uri'])) { - $graph->addResource($dataset_uri, 'dct:publisher', $definition['publisher_uri']); $graph->addResource($definition['publisher_uri'], 'a', 'foaf:Agent'); $graph->addLiteral($definition['publisher_uri'], 'foaf:name', $definition['publisher_name']); @@ -110,6 +118,7 @@ public function getDcatDocument(array $definitions, $oldest_definition) // Add the keywords to the dataset if (!empty($definition['keywords'])) { foreach (explode(',', $definition['keywords']) as $keyword) { + $keyword = trim($keyword); $graph->addLiteral($dataset_uri, 'dcat:keyword', $keyword); } } @@ -123,19 +132,15 @@ public function getDcatDocument(array $definitions, $oldest_definition) $optional = array('date', 'language', 'theme'); foreach ($optional as $dc_term) { - if (!empty($definition[$dc_term])) { - if ($dc_term == 'language') { - $lang = $this->languages->getByName($definition[$dc_term]); if (!empty($lang)) { $graph->addResource($dataset_uri, 'dct:' . $dc_term, 'http://lexvo.org/id/iso639-3/' . $lang['lang_id']); $graph->addResource('http://lexvo.org/id/iso639-3/' . $lang['lang_id'], 'a', 'dct:LinguisticSystem'); } - } else if ($dc_term == 'theme') { - + } elseif ($dc_term == 'theme') { $theme = $this->themes->getByLabel($definition[$dc_term]); if (!empty($theme)) { @@ -150,14 +155,23 @@ public function getDcatDocument(array $definitions, $oldest_definition) } // Add the distribution of the dataset - $graph->addResource($dataset_uri, 'dcat:distribution', $dataset_uri . '.json'); - $graph->addResource($dataset_uri . '.json', 'a', 'dcat:Distribution'); - $graph->addLiteral($dataset_uri . '.json', 'dct:description', 'A json feed of ' . $dataset_uri); - $graph->addLiteral($dataset_uri . '.json', 'dcat:mediaType', 'application/json'); + if ($this->isDataGeoFormatted($definition)) { + $distribution_uri = $dataset_uri . '.geojson'; + } else { + $distribution_uri = $dataset_uri . '.json'; + } + + $graph->addResource($dataset_uri, 'dcat:distribution', $distribution_uri); + $graph->addResource($distribution_uri, 'a', 'dcat:Distribution'); + $graph->addResource($distribution_uri, 'dcat:accessURL', $dataset_uri); + $graph->addResource($distribution_uri, 'dcat:downloadURL', $distribution_uri); + $graph->addLiteral($distribution_uri, 'dct:title', $title); + $graph->addLiteral($distribution_uri, 'dct:description', 'A json feed of ' . $dataset_uri); + $graph->addLiteral($distribution_uri, 'dcat:mediaType', 'application/json'); + $graph->addLiteral($distribution_uri, 'dct:issued', date(\DateTime::ISO8601, strtotime($definition['created_at']))); // Add the license to the distribution if (!empty($definition['rights'])) { - $license = $this->licenses->getByTitle($definition['rights']); if (!empty($license) && !empty($license['url'])) { @@ -171,6 +185,15 @@ public function getDcatDocument(array $definitions, $oldest_definition) return $graph; } + private function isDataGeoFormatted($definition) + { + return ( + $definition['type'] == 'shp' || + ($definition['type'] == 'json' && !empty($definition['geo_formatted']) && $definition['geo_formatted']) || + ($definition['type'] == 'xml' && !empty($definition['geo_formatted']) && $definition['geo_formatted']) + ); + } + /** * Return the issued date (in ISO8601 standard) of the catalog * diff --git a/app/Tdt/Core/Repositories/DefinitionRepository.php b/app/Tdt/Core/Repositories/DefinitionRepository.php index ba1c6b92..d98d2c71 100644 --- a/app/Tdt/Core/Repositories/DefinitionRepository.php +++ b/app/Tdt/Core/Repositories/DefinitionRepository.php @@ -6,10 +6,10 @@ class DefinitionRepository extends BaseDefinitionRepository implements DefinitionRepositoryInterface { - protected $rules = array( 'resource_name' => 'required', - 'collection_uri' => 'required|collectionuri' + 'collection_uri' => 'required|collectionuri', + 'contact_point' => 'uri', ); public function __construct(\Definition $model) @@ -116,7 +116,7 @@ public function getAll($limit = PHP_INT_MAX, $offset = 0) public function getAllPublished($limit = PHP_INT_MAX, $offset = 0) { - return \Definition::where('draft', '=', 0)->take($limit)->skip($offset)->get()->toArray(); + return \Definition::take($limit)->skip($offset)->get()->toArray(); } @@ -164,7 +164,7 @@ public function count() */ public function countPublished() { - return \Definition::where('draft', '=', 0)->count(); + return \Definition::count(); } public function getDefinitionSource($id, $name) @@ -183,7 +183,6 @@ private function validateType(array $input) // Use the power of the IoC try { - $type = ucfirst(strtolower($type)); $source_repository = $this->getSourceRepository($type); @@ -204,7 +203,6 @@ public function getAllFullDescriptions($limit = PHP_INT_MAX, $offset = 0) $definitions = array(); foreach ($this->getAll($limit, $offset) as $definition) { - $identifier = $definition['collection_uri'] . '/' . $definition['resource_name']; $definitions[$identifier] = $this->getFullDescription($identifier); } @@ -217,7 +215,6 @@ public function getAllDefinitionInfo($limit, $offset) $definitions = array(); foreach ($this->getAll($limit, $offset) as $definition) { - $identifier = $definition['collection_uri'] . '/' . $definition['resource_name']; $definitions[$identifier] = $this->getDescriptionInfo($identifier); } @@ -240,7 +237,6 @@ public function getDescriptionInfo($identifier) $properties['description'] = @$source_definition->description; unset($properties['map_property']); - unset($properties['draft']); return $properties; } @@ -271,7 +267,6 @@ public function getFullDescription($identifier) // If the source type has a relationship with tabular columns, then attach those to the properties if (method_exists(get_class($source_definition), 'tabularColumns')) { - $columns = $source_definition->tabularColumns(); $columns = $columns->getResults(); @@ -290,13 +285,11 @@ public function getFullDescription($identifier) // If the source type has a relationship with geoproperties, attach those to the properties if (method_exists(get_class($source_definition), 'geoProperties')) { - $geo_props = $source_definition->geoProperties(); $geo_props = $geo_props->getResults(); $geo_props_arr = array(); foreach ($geo_props as $geo_prop) { - $geo_entry = new \stdClass(); $geo_entry->path = $geo_prop->path; @@ -375,18 +368,6 @@ public function getCreateParameters() 'type' => 'integer', 'description' => 'How long this resource should be cached (in minutes).', ), - 'draft' => array( - 'required' => false, - 'name' => 'Draft', - 'type' => 'boolean', - 'description' => 'Draft definitions are not shown to the public when created, however the URI space they take is reserved.', - ), - 'map_property' => array( - 'required' => false, - 'name' => 'Map property', - 'type' => 'string', - 'description' => 'The property (e.g. column name) of the dataset that will be shown when a map visualization is applicable. Non geo-graphical datasets are not affected by this property.', - ), 'publisher_uri' => array( 'required' => false, 'name' => 'Publisher URI', @@ -408,6 +389,13 @@ public function getCreateParameters() 'description' => 'A comma separated list of keywords regarding the dataset.', 'group' => 'dc', ), + 'contact_point' => array( + 'required' => false, + 'name' => 'Contact point', + 'type' => 'string', + 'description' => 'A link on which people can provide feedback or flag errors.', + 'group' => 'dc', + ), ); } } diff --git a/app/Tdt/Core/Repositories/ElasticsearchDefinitionRepository.php b/app/Tdt/Core/Repositories/ElasticsearchDefinitionRepository.php new file mode 100644 index 00000000..b6c8d3e5 --- /dev/null +++ b/app/Tdt/Core/Repositories/ElasticsearchDefinitionRepository.php @@ -0,0 +1,80 @@ + 'required', + 'port' => 'integer', + 'es_index' => 'required', + 'es_type' => 'required', + 'description' => 'required', + ); + + public function __construct(\ElasticsearchDefinition $model) + { + $this->model = $model; + } + + /** + * Retrieve the set of create parameters that make up a Mongo definition. + * Include the parameters that make up relationships with this model. + */ + public function getAllParameters() + { + return array_merge($this->getCreateParameters()); + } + + /** + * Return the properties (= column fields) for this model. + */ + public function getCreateParameters() + { + return array( + 'description' => array( + 'required' => true, + 'name' => 'Description', + 'description' => 'The descriptive or informational string that provides some context for you published dataset.', + 'type' => 'text', + ), + 'host' => array( + 'required' => true, + 'name' => 'Host', + 'description' => 'The host of the MongoDB database.', + 'type' => 'string', + ), + 'es_index' => array( + 'required' => true, + 'name' => 'Index', + 'description' => 'The name of the index where data of a certain type resides.', + 'type' => 'string', + ), + 'es_type' => array( + 'required' => true, + 'name' => 'Type', + 'description' => 'The type of data that needs to be published.', + 'type' => 'string', + ), + 'port' => array( + 'required' => false, + 'name' => 'Port', + 'description' => 'The port of the Elasticsearch database where a connection can be set up.', + 'type' => 'string', + 'default_value' => 9200 + ), + 'username' => array( + 'required' => false, + 'name' => 'Username', + 'description' => 'A username that has read permissions on the provided index. Safety first, make sure the user only has read permissions.', + 'type' => 'string', + ), + 'password' => array( + 'required' => false, + 'name' => 'Password', + 'description' => 'The password for the user that has read permissions.', + 'type' => 'string', + ), + ); + } +} diff --git a/app/Tdt/Core/Repositories/GeoPropertyRepository.php b/app/Tdt/Core/Repositories/GeoPropertyRepository.php index 3ceb8888..630c09c4 100644 --- a/app/Tdt/Core/Repositories/GeoPropertyRepository.php +++ b/app/Tdt/Core/Repositories/GeoPropertyRepository.php @@ -7,7 +7,18 @@ class GeoPropertyRepository extends BaseDefinitionRepository implements GeoPropertyRepositoryInterface { - public static $geotypes = array('polygon', 'latitude', 'longitude', 'polyline', 'multiline', 'point'); + public static $geotypes = array('polygon', + 'latitude', + 'longitude', + 'polyline', + 'point', + 'multipoint', + 'polygonz', + 'elevation', + 'pointz', + 'multipointz', + 'polylinez' + ); public function __construct(\GeoProperty $model) { @@ -34,7 +45,6 @@ public function validateBulk(array $extracted_geo, array $provided_geo) // We don't have any extracted geo properties // If the provided ones qualify, validation is ok if (empty($extracted_geo)) { - $this->validate($provided_geo); return $provided_geo; @@ -44,7 +54,6 @@ public function validateBulk(array $extracted_geo, array $provided_geo) // The provided ones will have to be the same // as the extracted ones to pass validation if (!empty($extracted_geo)) { - if (!empty($provided_geo) && $extracted_geo != $provided_geo) { \App::abort(400, "The geo properties provided didn't match the geo properties that were extracted from the source."); } @@ -58,13 +67,11 @@ public function validateBulk(array $extracted_geo, array $provided_geo) public function validate(array $input) { foreach ($input as $geo) { - // Validate the parameters to their rules $validator = $this->getValidator($geo); // If any validation fails, return a message and abort the workflow if ($validator->fails()) { - $messages = $validator->messages(); \App::abort(400, $messages->first()); } diff --git a/app/Tdt/Core/Repositories/GeoprojectionRepository.php b/app/Tdt/Core/Repositories/GeoprojectionRepository.php new file mode 100644 index 00000000..6853ac64 --- /dev/null +++ b/app/Tdt/Core/Repositories/GeoprojectionRepository.php @@ -0,0 +1,24 @@ +first(); + + if (!empty($lang)) { + return $lang->toArray(); + } + + return $lang; + } + + public function getAll() + { + return \Geoprojection::all(array('epsg','projection'))->toArray(); + } +} diff --git a/app/Tdt/Core/Repositories/InstalledDefinitionRepository.php b/app/Tdt/Core/Repositories/InstalledDefinitionRepository.php index c92fe1cb..a6476beb 100644 --- a/app/Tdt/Core/Repositories/InstalledDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/InstalledDefinitionRepository.php @@ -46,7 +46,7 @@ public function getCreateParameters() 'required' => true, 'name' => 'Description', 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', + 'type' => 'text', ) ); } diff --git a/app/Tdt/Core/Repositories/Interfaces/JsonldDefinitionRepositoryInterface.php b/app/Tdt/Core/Repositories/Interfaces/ElasticsearchDefinitionRepositoryInterface.php similarity index 64% rename from app/Tdt/Core/Repositories/Interfaces/JsonldDefinitionRepositoryInterface.php rename to app/Tdt/Core/Repositories/Interfaces/ElasticsearchDefinitionRepositoryInterface.php index f24c5789..123115f2 100644 --- a/app/Tdt/Core/Repositories/Interfaces/JsonldDefinitionRepositoryInterface.php +++ b/app/Tdt/Core/Repositories/Interfaces/ElasticsearchDefinitionRepositoryInterface.php @@ -2,11 +2,11 @@ namespace Tdt\Core\Repositories\Interfaces; -interface JsonldDefinitionRepositoryInterface +interface ElasticsearchDefinitionRepositoryInterface { /** - * Return all JsonldDefinition objects + * Return all ElasticsearchDefinition objects * * @return array */ @@ -21,56 +21,57 @@ public function getAll(); public function getValidator(array $input); /** - * Return an array of create parameters with info attached - * e.g. array( 'create_parameter' => array( - * 'required' => true, - * 'description' => '...', - * 'type' => 'string', - * 'name' => 'pretty name' - * ), ...) + * Store a ElasticsearchDefinition object * - * @return array + * @param array $input + * @return array ElasticsearchDefinition */ - public function getCreateParameters(); + public function store(array $input); /** - * Return an array of all the create parameters, also the parameters - * that are necessary for further internal relationships + * Update a ElasticsearchDefinition object * - * @return array + * @param integer $model_id + * @param array $input + * @return array ElasticsearchDefinition */ - public function getAllParameters(); + public function update($model_id, array $input); /** - * Store a JsonldDefinition + * Delete a ElasticsearchDefinition * - * @param array $input - * @return array JsonldDefinition + * @param integer $model_id + * @return boolean|null */ - public function store(array $input); + public function delete($model_id); /** - * Update a JsonldDefinition + * Fetch a ElasticsearchDefinition by id * - * @param integer $id - * @param array $input - * @return array JsonldDefinition + * @param integer $model_id + * @return array object */ - public function update($id, array $input); + public function getById($model_id); /** - * Delete a JsonldDefinition + * Return an array of create parameters with info attached + * e.g. array( 'create_parameter' => array( + * 'required' => true, + * 'description' => '...', + * 'type' => 'string', + * 'name' => 'pretty name' + * ), ...) * - * @param integer $id - * @return boolean|null + * @return array */ - public function delete($id); + public function getCreateParameters(); /** - * Fetch a JsonldDefinition by id + * Return an array of all the create parameters, also the parameters + * that are necessary for further internal relationships + * * - * @param integer $id - * @return array JsonldDefinition + * @return array */ - public function getById($id); + public function getAllParameters(); } diff --git a/app/Tdt/Core/Repositories/Interfaces/GeoprojectionRepositoryInterface.php b/app/Tdt/Core/Repositories/Interfaces/GeoprojectionRepositoryInterface.php new file mode 100644 index 00000000..5bd1e74f --- /dev/null +++ b/app/Tdt/Core/Repositories/Interfaces/GeoprojectionRepositoryInterface.php @@ -0,0 +1,22 @@ + array( + * 'required' => true, + * 'description' => '...', + * 'type' => 'string', + * 'name' => 'pretty name' + * ), ...) + * + * @return array + */ + public function getCreateParameters(); + + /** + * Return an array of all the create parameters, also the parameters + * that are necessary for further internal relationships + * + * (e.g. Mysql needs columns, in an RDBMS as back-end this results in model relationships) + * @return array + */ + public function getAllParameters(); +} diff --git a/app/Tdt/Core/Repositories/JsonDefinitionRepository.php b/app/Tdt/Core/Repositories/JsonDefinitionRepository.php index 20d78f8e..eb451204 100644 --- a/app/Tdt/Core/Repositories/JsonDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/JsonDefinitionRepository.php @@ -40,8 +40,16 @@ public function getCreateParameters() 'required' => true, 'name' => 'Description', 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', - ) + 'type' => 'text', + ), + 'jsontype' => array( + 'required' => true, + 'name' => 'JSON type', + 'description' => 'What kind of JSON is it?', + 'type' => 'list', + 'list' => 'Plain|GeoJSON|JSON-LD', + 'default_value' => false, + ), ); } } diff --git a/app/Tdt/Core/Repositories/JsonldDefinitionRepository.php b/app/Tdt/Core/Repositories/JsonldDefinitionRepository.php deleted file mode 100644 index 7c383a85..00000000 --- a/app/Tdt/Core/Repositories/JsonldDefinitionRepository.php +++ /dev/null @@ -1,47 +0,0 @@ - 'json|uri|required', - 'description' => 'required', - ); - - public function __construct(\JsonldDefinition $model) - { - $this->model = $model; - } - - /** - * Retrieve the set of create parameters that make up a JSON definition. - */ - public function getCreateParameters() - { - return array( - 'uri' => array( - 'required' => true, - 'name' => 'URI', - 'description' => 'The location of the JSON file, this should either be a URL or a local file location.', - 'type' => 'string', - ), - 'title' => array( - 'required' => true, - 'name' => 'Title', - 'description' => 'A name given to the resource.', - 'type' => 'string', - ), - 'description' => array( - 'required' => true, - 'name' => 'Description', - 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', - ) - ); - } -} diff --git a/app/Tdt/Core/Repositories/LicenseRepository.php b/app/Tdt/Core/Repositories/LicenseRepository.php index 87b35edb..ad4b691e 100644 --- a/app/Tdt/Core/Repositories/LicenseRepository.php +++ b/app/Tdt/Core/Repositories/LicenseRepository.php @@ -6,13 +6,11 @@ class LicenseRepository implements LicenseRepositoryInterface { - /** * Fetch a License by its title (=id) */ public function getByTitle($title) { - $license = \License::where('title', '=', $title)->first(); if (!empty($license)) { @@ -26,16 +24,7 @@ public function getAll() { return \License::all( array( - 'domain_content', - 'domain_data', - 'domain_software', - 'family', 'license_id', - 'is_generic', - 'is_okd_compliant', - 'is_osi_compliant', - 'maintainer', - 'status', 'title', 'url' ) diff --git a/app/Tdt/Core/Repositories/MongoDefinitionRepository.php b/app/Tdt/Core/Repositories/MongoDefinitionRepository.php new file mode 100644 index 00000000..36525eaf --- /dev/null +++ b/app/Tdt/Core/Repositories/MongoDefinitionRepository.php @@ -0,0 +1,80 @@ + 'required', + 'port' => 'integer', + 'database' => 'required', + 'mongo_collection' => 'required', + 'description' => 'required', + ); + + public function __construct(\MongoDefinition $model) + { + $this->model = $model; + } + + /** + * Retrieve the set of create parameters that make up a Mongo definition. + * Include the parameters that make up relationships with this model. + */ + public function getAllParameters() + { + return array_merge($this->getCreateParameters()); + } + + /** + * Return the properties (= column fields) for this model. + */ + public function getCreateParameters() + { + return array( + 'description' => array( + 'required' => true, + 'name' => 'Description', + 'description' => 'The descriptive or informational string that provides some context for you published dataset.', + 'type' => 'text', + ), + 'host' => array( + 'required' => true, + 'name' => 'Host', + 'description' => 'The host of the MongoDB database.', + 'type' => 'string', + ), + 'database' => array( + 'required' => true, + 'name' => 'Database', + 'description' => 'The name of the database where the collection, that needs to be published, resides.', + 'type' => 'string', + ), + 'mongo_collection' => array( + 'required' => true, + 'name' => 'Collection', + 'description' => 'The collection of the database.', + 'type' => 'string', + ), + 'port' => array( + 'required' => false, + 'name' => 'Port', + 'description' => 'The port of the Mongo database where a connection can be set up.', + 'type' => 'string', + 'default_value' => 27017 + ), + 'username' => array( + 'required' => false, + 'name' => 'Username', + 'description' => 'A username that has read permissions on the provided collection. Safety first, make sure the user only has read permissions.', + 'type' => 'string', + ), + 'password' => array( + 'required' => false, + 'name' => 'Password', + 'description' => 'The password for the user that has read permissions.', + 'type' => 'string', + ), + ); + } +} diff --git a/app/Tdt/Core/Repositories/MysqlDefinitionRepository.php b/app/Tdt/Core/Repositories/MysqlDefinitionRepository.php index f7d11e5c..0b868081 100644 --- a/app/Tdt/Core/Repositories/MysqlDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/MysqlDefinitionRepository.php @@ -6,13 +6,13 @@ class MysqlDefinitionRepository extends TabularBaseRepository implements MysqlDefinitionRepositoryInterface { - protected $rules = array( 'host' => 'required', 'port' => 'integer', 'database' => 'required', 'username' => 'required', 'query' => 'required|mysqlquery', + 'description' => 'required' ); public function __construct(\MysqlDefinition $model) @@ -141,6 +141,12 @@ public function getCreateParameters() 'default_value' => '', 'type' => 'string', ), + 'description' => array( + 'required' => true, + 'name' => 'Description', + 'description' => 'The descriptive or informational string that provides some context for you published dataset.', + 'type' => 'text', + ), 'collation' => array( 'required' => false, 'name' => 'Collation', diff --git a/app/Tdt/Core/Repositories/RdfDefinitionRepository.php b/app/Tdt/Core/Repositories/RdfDefinitionRepository.php index 293c242a..b4758e55 100644 --- a/app/Tdt/Core/Repositories/RdfDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/RdfDefinitionRepository.php @@ -31,7 +31,7 @@ public function getCreateParameters() 'uri' => array( 'required' => true, 'name' => 'URI', - 'description' => 'The URI of the turtle file.', + 'description' => 'The URI of the RDF file.', 'type' => 'string', ), 'title' => array( @@ -44,7 +44,7 @@ public function getCreateParameters() 'required' => true, 'name' => 'Description', 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', + 'type' => 'text', ), 'format' => array( 'required' => true, diff --git a/app/Tdt/Core/Repositories/ShpDefinitionRepository.php b/app/Tdt/Core/Repositories/ShpDefinitionRepository.php index 4673f72c..c86e1486 100644 --- a/app/Tdt/Core/Repositories/ShpDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/ShpDefinitionRepository.php @@ -52,14 +52,16 @@ public function getCreateParameters() 'required' => true, 'name' => 'Description', 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', + 'type' => 'text', ), 'epsg' => array( 'required' => false, 'name' => 'EPSG code', 'description' => 'This parameter holds the EPSG code in which the geometric properties in the shape file are encoded.', - 'default_value' => 4326, - 'type' => 'string', + 'default_value' => "4326", + 'type' => 'list', + 'list' => 'api/geoprojections', + 'list_option' => 'epsg', ) ); } @@ -70,13 +72,13 @@ public function getCreateParameters() */ public function getAllParameters() { - $column_params = array( + $column_params = array( 'columns' => array( 'description' => 'Columns must be an array of objects of which the template is described in the parameters section.', 'parameters' => $this->tabular_repository->getCreateParameters(), ) - ); + ); return array_merge($this->getCreateParameters(), $column_params); } diff --git a/app/Tdt/Core/Repositories/SparqlDefinitionRepository.php b/app/Tdt/Core/Repositories/SparqlDefinitionRepository.php index 7fa958b5..3fa84819 100644 --- a/app/Tdt/Core/Repositories/SparqlDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/SparqlDefinitionRepository.php @@ -40,7 +40,7 @@ public function getCreateParameters() 'required' => true, 'name' => 'Description', 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', + 'type' => 'text', ), 'query' => array( 'required' => true, diff --git a/app/Tdt/Core/Repositories/TabularBaseRepository.php b/app/Tdt/Core/Repositories/TabularBaseRepository.php index eb748622..93c76e45 100644 --- a/app/Tdt/Core/Repositories/TabularBaseRepository.php +++ b/app/Tdt/Core/Repositories/TabularBaseRepository.php @@ -41,7 +41,9 @@ public function store(array $input) $geo = $input['geo']; } - $geo = $this->geo_repository->validateBulk($extracted_geo, $geo); + if (!empty($geo) || !empty($extracted_geo)) { + $geo = $this->geo_repository->validateBulk($extracted_geo, $geo); + } // Validation has been done, lets create the models $input = array_only($input, array_keys($this->getCreateParameters())); @@ -74,7 +76,7 @@ public function update($tabular_id, array $input) $model_name = $this->getModelName(); // Validate the column properties (perhaps we need to put this extraction somewhere else) - $extracted_columns = $this->extractColumns($model_definition); + $extracted_columns = $this->extractColumns($input); $input_columns = @$input['columns']; @@ -94,7 +96,11 @@ public function update($tabular_id, array $input) $geo = $input['geo']; } - $geo = $this->geo_repository->validateBulk($extracted_geo, $geo); + if (!empty($geo) || !empty($extracted_geo)) { + $geo = $this->geo_repository->validateBulk($extracted_geo, $geo); + } elseif (!isset($geo)) { + $geo = $this->geo_repository->getGeoProperties($tabular_id, $model_name); + } // Validation has been done, lets create the models $input = array_only($input, array_keys($this->getCreateParameters())); diff --git a/app/Tdt/Core/Repositories/XlsDefinitionRepository.php b/app/Tdt/Core/Repositories/XlsDefinitionRepository.php index 7a9055b3..be2727c1 100644 --- a/app/Tdt/Core/Repositories/XlsDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/XlsDefinitionRepository.php @@ -52,7 +52,7 @@ public function getCreateParameters() 'required' => true, 'name' => 'Description', 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', + 'type' => 'text', ), 'sheet' => array( 'required' => false, @@ -81,6 +81,12 @@ public function getCreateParameters() 'description' => 'This is a shortcut to define a primary key of this dataset. The value must be the index of the column you want each row to be mapped on. The pk property will never explicitly appear in the definition, but will manifest itself as part of a column property.', 'type' => 'integer', ), + 'map_property' => array( + 'required' => false, + 'name' => 'Map property', + 'type' => 'string', + 'description' => 'The property (e.g. column name) of the dataset that will be displayed when a map visualization is applicable.', + ), ); } @@ -90,12 +96,12 @@ public function getCreateParameters() */ public function getAllParameters() { - $column_params = array( + $column_params = array( 'columns' => array('description' => 'Columns must be an array of objects of which the template is described in the parameters section.', 'parameters' => $this->tabular_repository->getCreateParameters(), - ), - ); + ), + ); return array_merge($this->getCreateParameters(), $column_params); } diff --git a/app/Tdt/Core/Repositories/XmlDefinitionRepository.php b/app/Tdt/Core/Repositories/XmlDefinitionRepository.php index 777f38bc..f0fd6907 100644 --- a/app/Tdt/Core/Repositories/XmlDefinitionRepository.php +++ b/app/Tdt/Core/Repositories/XmlDefinitionRepository.php @@ -39,8 +39,15 @@ public function getCreateParameters() 'required' => true, 'name' => 'Description', 'description' => 'The descriptive or informational string that provides some context for you published dataset.', - 'type' => 'string', - ) + 'type' => 'text', + ), + 'geo_formatted' => array( + 'required' => true, + 'name' => 'KML', + 'description' => 'Is the XML document a KML document?', + 'type' => 'boolean', + 'default_value' => false, + ), ); } } diff --git a/app/Tdt/Core/Tests/Api/DiscoveryTest.php b/app/Tdt/Core/Tests/Api/DiscoveryTest.php index 5720118c..d727c7a0 100644 --- a/app/Tdt/Core/Tests/Api/DiscoveryTest.php +++ b/app/Tdt/Core/Tests/Api/DiscoveryTest.php @@ -29,8 +29,9 @@ public function testDiscovery() $this->assertNotNull($document->resources->definitions->methods->put->body->json); $this->assertNotNull($document->resources->definitions->methods->put->body->shp); $this->assertNotNull($document->resources->definitions->methods->put->body->xls); - $this->assertNotNull($document->resources->definitions->methods->put->body->jsonld); $this->assertNotNull($document->resources->definitions->methods->put->body->sparql); $this->assertNotNull($document->resources->definitions->methods->put->body->rdf); + $this->assertNotNull($document->resources->definitions->methods->put->body->elasticsearch); + $this->assertNotNull($document->resources->definitions->methods->put->body->mongo); } } diff --git a/app/Tdt/Core/Tests/Api/JsonldTest.php b/app/Tdt/Core/Tests/Api/JsonldTest.php index 3e8d7d20..1250774c 100644 --- a/app/Tdt/Core/Tests/Api/JsonldTest.php +++ b/app/Tdt/Core/Tests/Api/JsonldTest.php @@ -7,7 +7,7 @@ use Tdt\Core\Datasets\DatasetController; use Symfony\Component\HttpFoundation\Request; use \Definition; -use \JsonldDefinition; +use \JsonDefinition; class JsonldTest extends TestCase { @@ -31,13 +31,11 @@ public function testPutApi() { // Publish each json file in the test json data folder. foreach ($this->test_data as $file_config) { - $name = $file_config['cname']; $uri = ''; if ($file_config['type'] == 'file') { - $file = $file_config['uri']; $uri = app_path() . "/storage/data/tests/jsonld/$file.jsonld"; @@ -49,7 +47,8 @@ public function testPutApi() $data = array( 'description' => "A JSON-LD publication from the $name jsonld file.", 'uri' => $uri, - 'type' => 'jsonld' + 'type' => 'json', + 'jsontype' => 'JSON-LD' ); // Set the headers. @@ -73,7 +72,6 @@ public function testGetApi() { // Request the data for each of the test json-ld files. foreach ($this->test_data as $file_config) { - $name = $file_config['cname']; $file = 'jsonld/'. $name .'.jsonld'; @@ -89,7 +87,6 @@ public function testGetApi() public function testUpdateApi() { foreach ($this->test_data as $file_config) { - $name = $file_config['cname']; $updated_description = 'An updated description for ' . $name; @@ -118,7 +115,6 @@ public function testDeleteApi() { // Delete the published definition for each test json file. foreach ($this->test_data as $file_config) { - $name = $file_config['cname']; $this->updateRequest('DELETE'); @@ -131,7 +127,7 @@ public function testDeleteApi() // Check if everything is deleted properly. $definitions_count = Definition::all()->count(); - $jsonld_count = JsonldDefinition::all()->count(); + $jsonld_count = JsonDefinition::where('jsontype', 'JSON-LD')->count(); $this->assertEquals(0, $jsonld_count); $this->assertEquals(0, $definitions_count); diff --git a/app/Tdt/Core/Tests/Api/ModelPagingTest.php b/app/Tdt/Core/Tests/Api/ModelPagingTest.php index 77a2c4ba..d02fc9e3 100644 --- a/app/Tdt/Core/Tests/Api/ModelPagingTest.php +++ b/app/Tdt/Core/Tests/Api/ModelPagingTest.php @@ -29,7 +29,6 @@ public function testPutApi() // Add the CSV definitions foreach ($this->test_data as $file) { - // Set the definition parameters. $data = array( 'description' => "A CSV publication from the $file csv file.", @@ -88,7 +87,6 @@ public function testDeleteApi() // Delete the published definition for each test csv file. foreach ($this->test_data as $file) { - $this->updateRequest('DELETE'); $controller = \App::make('Tdt\Core\Definitions\DefinitionController'); @@ -127,18 +125,14 @@ private function processLinkHeader($response) // Check for link to next and last // Don't let the order of these links be a hassle foreach ($links as $link) { - if (preg_match('/(.*)\?(limit|offset)=(\d+)&(limit|offset)=(\d+);rel=(.*)/', $link, $matches)) { - - if ($matches[6] == 'last') { - + if ($matches[6] == 'http://www.w3.org/ns/hydra/core#lastPage') { if ($matches[2] == 'offset') { $this->assertEquals($matches[3], 6); } else { $this->assertEquals($matches[5], 2); } } else { - if ($matches[2] == 'offset') { $this->assertEquals($matches[3], 2); } else { @@ -169,11 +163,9 @@ private function processDcat() $this->assertEquals(2, count($datasets)); foreach ($datasets as $dataset) { - $literal_properties = ['dc:title', 'dc:description', 'dc:identifier', 'dc:issued', 'dc:modified']; foreach ($literal_properties as $property) { - $literal = $dataset->getLiteral($property); $this->assertNotEmpty($literal); diff --git a/app/Tdt/Core/Tests/Api/ShpTest.php b/app/Tdt/Core/Tests/Api/ShpTest.php index f90f0cb3..e0055921 100644 --- a/app/Tdt/Core/Tests/Api/ShpTest.php +++ b/app/Tdt/Core/Tests/Api/ShpTest.php @@ -22,10 +22,13 @@ class ShpTest extends TestCase public function testPutApi() { + \Geoprojection::create([ + 'epsg' => 4326, + 'projection' => "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]" + ]); // Publish each shp file in the test shp data folder. foreach ($this->test_data as $entry) { - $name = $entry['name']; $file = $entry['file']; @@ -55,10 +58,8 @@ public function testPutApi() public function testGetApi() { - // Request the data for each of the test shp files. foreach ($this->test_data as $entry) { - $name = $entry['name']; $uri = 'shp/'. $name .'.json'; @@ -74,7 +75,6 @@ public function testGetApi() public function testUpdateApi() { foreach ($this->test_data as $entry) { - $file = $entry['name']; $updated_description = 'An updated description for ' . $file; diff --git a/app/Tdt/Core/Tests/Commands/ExportImportTest.php b/app/Tdt/Core/Tests/Commands/ExportImportTest.php index ceb404b2..e0228018 100644 --- a/app/Tdt/Core/Tests/Commands/ExportImportTest.php +++ b/app/Tdt/Core/Tests/Commands/ExportImportTest.php @@ -46,7 +46,7 @@ public function testExportDefinitions() $this->assertTrue(!empty($export_definitions)); - $this->assertEquals(6, count($export_definitions)); + $this->assertEquals(5, count($export_definitions)); // Write the output to a file, necessary to be using in the import if (!empty($export_body)) { diff --git a/app/Tdt/Core/Tests/Data/Spectql/SpectqlQueries.php b/app/Tdt/Core/Tests/Data/Spectql/SpectqlQueries.php deleted file mode 100644 index 44da76da..00000000 --- a/app/Tdt/Core/Tests/Data/Spectql/SpectqlQueries.php +++ /dev/null @@ -1,190 +0,0 @@ - array( - 'geo' => array( - 'definition' => array( - 'type' => 'csv', - 'delimiter' => ';', - 'uri' => "/csv/geo_csv.csv", - 'description' => 'csv geo', - ), - 'queries' => array( - // select all without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{*}:json", - 'result_count' => 399, - 'first_result' => '{"lon":"61.33","lat":"32.4","Unit_Type":"District","Dist_Name":"Qala-e-Kah","Prov_Name":"Farah","Dist_ID":"3106","Prov_ID":"31"}', - ), - // select all with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{*}?Unit_Type>'District'&Dist_Name>'Pusht Rod':json", - 'result_count' => 117, - 'first_result' => '{"lon":"61.33","lat":"32.4","Unit_Type":"District","Dist_Name":"Qala-e-Kah","Prov_Name":"Farah","Dist_ID":"3106","Prov_ID":"31"}', - ), - // select columns with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{lat, Dist_Name}?Unit_Type>'District'&Dist_Name>'Pusht Rod':json", - 'result_count' => 117, - 'first_result' => '{"lat":"32.4","Dist_Name":"Qala-e-Kah"}', - ), - // average without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{avg(lon)}:json", - 'result_count' => 1, - 'first_result' => '{"avg_lon":67.793634085213}', - ), - // average with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{avg(lat)}?Prov_Name=='Uruzgan':json", - 'result_count' => 1, - 'first_result' => '{"avg_lat":32.822}', - ), - // count without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{count(lat)}:json", - 'result_count' => 1, - 'first_result' => '{"count_lat":399}', - ), - // count with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{count(lat)}?Prov_Name=='Uruzgan':json", - 'result_count' => 1, - 'first_result' => '{"count_lat":5}', - ), - // first without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{first(Prov_Name)}:json", - 'result_count' => 1, - 'first_result' => '{"first_Prov_Name":"Farah"}', - ), - // first with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{first(Prov_Name)}?Dist_Name>'F':json", - 'result_count' => 1, - 'first_result' => '{"first_Prov_Name":"Farah"}', - ), - // last without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{last(Prov_Name)}:json", - 'result_count' => 1, - 'first_result' => '{"last_Prov_Name":"Balkh"}', - ), - // last with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{last(Prov_Name)}?Dist_Name>'F':json", - 'result_count' => 1, - 'first_result' => '{"last_Prov_Name":"Balkh"}', - ), - // max without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{max(lat)}:json", - 'result_count' => 1, - 'first_result' => '{"max_lat":38.23}', - ), - // max with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{max(lat)}?Prov_Name=='Uruzgan':json", - 'result_count' => 1, - 'first_result' => '{"max_lat":33}', - ), - // min without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{min(lat)}:json", - 'result_count' => 1, - 'first_result' => '{"min_lat":29.88}', - ), - // min with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{min(lat)}?Prov_Name=='Uruzgan':json", - 'result_count' => 1, - 'first_result' => '{"min_lat":32.58}', - ), - // sum without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{sum(lat)}:json", - 'result_count' => 1, - 'first_result' => '{"sum_lat":13799.93}', - ), - // sum with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{sum(lat)}?Prov_Name=='Uruzgan':json", - 'result_count' => 1, - 'first_result' => '{"sum_lat":164.11}', - ), - // ucase without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{ucase(Prov_Name)}:json", - 'result_count' => 399, - 'first_result' => '{"ucase_Prov_Name":"FARAH"}', - ), - // ucase with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{ucase(Prov_Name)}?Prov_Name=='Uruzgan':json", - 'result_count' => 5, - 'first_result' => '{"ucase_Prov_Name":"URUZGAN"}', - ), - // lcase without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{lcase(Prov_Name)}:json", - 'result_count' => 399, - 'first_result' => '{"lcase_Prov_Name":"farah"}', - ), - // lcase with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{lcase(Prov_Name)}?Prov_Name=='Uruzgan':json", - 'result_count' => 5, - 'first_result' => '{"lcase_Prov_Name":"uruzgan"}', - ), - // len without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{len(Prov_Name)}:json", - 'result_count' => 399, - 'first_result' => '{"len_Prov_Name":5}', - ), - // len with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{len(Prov_Name)}?Prov_Name=='Uruzgan':json", - 'result_count' => 5, - 'first_result' => '{"len_Prov_Name":7}', - ), - // asort without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{asort(Prov_Name),Dist_Name}:json", - 'result_count' => 399, - 'first_result' => '{"Prov_Name":"Badakhshan","Dist_Name":"Shahr-e-Buzorg"}', - ), - // asort with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{asort(Prov_Name),Dist_Name}?Dist_Name<'F':json", - 'result_count' => 105, - 'first_result' => '{"Prov_Name":"Badakhshan","Dist_Name":"Darwaz"}', - ), - // dsort without filter - array( - 'query' => "http://localhost/spectql/tabular/geo{dsort(Prov_Name),Dist_Name}:json", - 'result_count' => 399, - 'first_result' => '{"Prov_Name":"Zabul","Dist_Name":"Tarnak Wa Jaldak"}', - ), - // dsort with filter - array( - 'query' => "http://localhost/spectql/tabular/geo{dsort(Prov_Name),Dist_Name}?Dist_Name<'F':json", - 'result_count' => 105, - 'first_result' => '{"Prov_Name":"Zabul","Dist_Name":"Atghar"}', - ), - ), - ), - ), - ); -} diff --git a/app/Tdt/Core/Tests/TestCase.php b/app/Tdt/Core/Tests/TestCase.php index 91f13a2c..deb6f2fd 100644 --- a/app/Tdt/Core/Tests/TestCase.php +++ b/app/Tdt/Core/Tests/TestCase.php @@ -55,14 +55,13 @@ public static function tearDownAfterClass() \CsvDefinition::truncate(); \InstalledDefinition::truncate(); \JsonDefinition::truncate(); - // RdfDefinition::truncate(); \ShpDefinition::truncate(); \SparqlDefinition::truncate(); \XlsDefinition::truncate(); \XmlDefinition::truncate(); \GeoProperty::truncate(); \TabularColumns::truncate(); - \JsonldDefinition::truncate(); + \Geoprojection::truncate(); } /** @@ -70,7 +69,6 @@ public static function tearDownAfterClass() */ public function updateRequest($method, $headers = array(), $data = array()) { - // Log in as admin - header $headers['Authorization'] = 'Basic YWRtaW46YWRtaW4='; diff --git a/app/Tdt/Core/Tests/Ui/DatasetControllerAdminTest.php b/app/Tdt/Core/Tests/Ui/DatasetControllerAdminTest.php index 94bf958b..cba5464a 100644 --- a/app/Tdt/Core/Tests/Ui/DatasetControllerAdminTest.php +++ b/app/Tdt/Core/Tests/Ui/DatasetControllerAdminTest.php @@ -10,9 +10,6 @@ class DatasetControllerAdminTest extends BaseUITest */ public function testRedirect() { - // var_dump(); - // var_dump(get_class($this->client)); - // die(); $crawler = $this->client->request('GET', '/api/admin'); $this->assertRedirectedTo('/api/admin/datasets'); } @@ -27,7 +24,6 @@ public function testIndex() $this->assertCount(1, $crawler->filter('h3:contains("Manage your data")')); $this->assertCount(1, $crawler->filter('li.active > a:contains("Datasets")')); - $this->assertCount(1, $crawler->filter('h4 > a:contains("france/places")')); } public function testAdd() diff --git a/app/Tdt/Core/Tests/Ui/HTMLFormatterTest.php b/app/Tdt/Core/Tests/Ui/HTMLFormatterTest.php index 600678bc..6a58ee4f 100644 --- a/app/Tdt/Core/Tests/Ui/HTMLFormatterTest.php +++ b/app/Tdt/Core/Tests/Ui/HTMLFormatterTest.php @@ -35,6 +35,11 @@ public function testCodeView() */ public function testMapView() { + \Geoprojection::create([ + 'epsg' => 4326, + 'projection' => "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]" + ]); + $crawler = $this->client->request('GET', '/dresden/rivers'); $this->assertResponseOk(); diff --git a/app/Tdt/Core/Tests/Ui/HomeControllerTest.php b/app/Tdt/Core/Tests/Ui/HomeControllerTest.php index b731b8f6..2398867d 100644 --- a/app/Tdt/Core/Tests/Ui/HomeControllerTest.php +++ b/app/Tdt/Core/Tests/Ui/HomeControllerTest.php @@ -10,7 +10,6 @@ class HomeControllerTest extends BaseUITest */ public function testIndex() { - \Artisan::call('db:seed', array('--class'=>'DemoDataSeeder')); $crawler = $this->client->request('GET', '/'); $this->assertResponseOk(); diff --git a/app/Tdt/Core/Ui/DatasetController.php b/app/Tdt/Core/Ui/DatasetController.php index b7c3ded3..025f624f 100644 --- a/app/Tdt/Core/Ui/DatasetController.php +++ b/app/Tdt/Core/Ui/DatasetController.php @@ -1,10 +1,12 @@ + * @author Jan Vansteenlandt */ namespace Tdt\Core\Ui; @@ -18,7 +20,6 @@ class DatasetController extends UiController */ public function getIndex() { - // Set permission Auth::requirePermissions('admin.dataset.view'); @@ -35,7 +36,6 @@ public function getIndex() */ public function getAdd() { - // Set permission Auth::requirePermissions('admin.dataset.create'); @@ -47,8 +47,8 @@ public function getAdd() // Sort parameters for each media type $mediatypes = array(); $lists = array(); - foreach ($mediatypes_spec as $mediatype => $type) { + foreach ($mediatypes_spec as $mediatype => $type) { $parameters_required = array(); $parameters_optional = array(); $parameters_dc = array(); @@ -56,14 +56,10 @@ public function getAdd() $parameters_geo = array(); foreach ($type->parameters as $parameter => $object) { - // Filter array type parameters - if (empty($object->parameters)) { - // Filter Dublin core parameters if (!empty($object->group) && $object->group == 'dc') { - // Fetch autocomplete DC fields if ($object->type == 'list') { $uri = $object->list; @@ -86,13 +82,34 @@ public function getAdd() } - $parameters_dc[$parameter] = $object; } else { - // Fitler optional vs required + // Filter optional vs required + if ($object->type == 'list' && (strpos($object->list, '|') !== false)) { + $object->list = explode('|', $object->list); + } elseif ($object->type == 'list') { + $uri = $object->list; + + // Check list cache + if (empty($lists[$uri])) { + $data = json_decode($this->getDocument($uri)); + $data_set = array(); + + foreach ($data as $o) { + if (!empty($o->{$object->list_option})) { + $data_set[] = $o->{$object->list_option}; + } + } + + $lists[$uri] = $data_set; + } + + $object->list = $lists[$uri]; + } + if ($object->required) { - // Filter the type paramter + // Filter the type parameter if ($parameter != 'type') { $parameters_required[$parameter] = $object; } @@ -101,8 +118,6 @@ public function getAdd() } } } else { - - switch ($parameter) { case 'columns': foreach ($object->parameters as $param => $obj) { @@ -115,7 +130,6 @@ public function getAdd() } break; } - } } @@ -125,6 +139,13 @@ public function getAdd() // TODO special treatment for caching unset($parameters_optional['draft']); + // Translate the parameters + $parameters_required = $this->translateParameters($parameters_required, $mediatype); + $parameters_optional = $this->translateParameters($parameters_optional, $mediatype); + $parameters_dc = $this->translateParameters($parameters_dc, 'definition'); + $parameters_columns = $this->translateParameters($parameters_columns, $mediatype); + $parameters_geo = $this->translateParameters($parameters_geo, $mediatype); + $mediatypes[$mediatype]['parameters_required'] = $parameters_required; $mediatypes[$mediatype]['parameters_optional'] = $parameters_optional; $mediatypes[$mediatype]['parameters_dc'] = $parameters_dc; @@ -145,13 +166,11 @@ public function getAdd() */ public function getEdit($id) { - // Set permission Auth::requirePermissions('admin.dataset.update'); $definition = \Definition::find($id); if ($definition) { - // Get source defintion $source_definition = $definition->source()->first(); @@ -170,20 +189,16 @@ public function getEdit($id) $lists = array(); foreach ($mediatype->parameters as $parameter => $object) { - // Filter array type parameters if (empty($object->parameters)) { - // Filter Dublin core parameters if (!empty($object->group) && $object->group == 'dc') { - // Fetch autocomplete DC fields if ($object->type == 'list') { $uri = $object->list; // Check list cache if (empty($lists[$uri])) { - $data = json_decode($this->getDocument($uri)); $data_set = array(); @@ -203,6 +218,29 @@ public function getEdit($id) $parameters_dc[$parameter] = $object; } else { // Filter optional vs required + // Filter optional vs required + if ($object->type == 'list' && (strpos($object->list, '|') !== false)) { + $object->list = explode('|', $object->list); + } elseif ($object->type == 'list') { + $uri = $object->list; + + // Check list cache + if (empty($lists[$uri])) { + $data = json_decode($this->getDocument($uri)); + $data_set = array(); + + foreach ($data as $o) { + if (!empty($o->{$object->list_option})) { + $data_set[] = $o->{$object->list_option}; + } + } + + $lists[$uri] = $data_set; + } + + $object->list = $lists[$uri]; + } + $parameters_optional[$parameter] = $object; } } @@ -211,8 +249,6 @@ public function getEdit($id) // Filter on unnecessary optional parameters unset($parameters_optional['cache_minutes']); - - // TODO special treatment for draft unset($parameters_optional['draft']); return \View::make('ui.datasets.edit') @@ -282,4 +318,28 @@ private function getDocument($uri) // Document content return $response->getContent(); } + + /** + * Translate the view properties of the parameters + * + * @param array $parameters + * @param string $media_type + * + * @return array + */ + private function translateParameters($parameters, $media_type) + { + $translatedParameters = []; + + foreach ($parameters as $name => $param) { + $trans_param_name = $media_type . '_' . $name; + $trans_param_desc_name = $trans_param_name . '_desc'; + + $param->name = trans('parameters.' . $trans_param_name); + $param->description = trans('parameters.' . $trans_param_desc_name); + $translatedParameters[$name] = $param; + } + + return $translatedParameters; + } } diff --git a/app/Tdt/Core/Ui/LanguageController.php b/app/Tdt/Core/Ui/LanguageController.php new file mode 100644 index 00000000..cf2cd9cd --- /dev/null +++ b/app/Tdt/Core/Ui/LanguageController.php @@ -0,0 +1,27 @@ + + */ +namespace Tdt\Core\Ui; + +use Cookie; +use Redirect; + +class LanguageController extends \Controller +{ + + /** + * Change the UI language + */ + public function setLanguage($lang) + { + if ($lang && strlen($lang) == 2) { + Cookie::queue('locale', $lang, 0); + } + + return Redirect::back(); + } +} diff --git a/app/Tdt/Core/Ui/UiController.php b/app/Tdt/Core/Ui/UiController.php index 96648d4f..5a4e1f63 100644 --- a/app/Tdt/Core/Ui/UiController.php +++ b/app/Tdt/Core/Ui/UiController.php @@ -8,6 +8,9 @@ namespace Tdt\Core\Ui; use Tdt\Core\Auth\Auth; +use Config; +use App; +use Cookie; class UiController extends \Controller { @@ -58,25 +61,48 @@ public function __construct() $menu = $this->core_menu; + // UI translation + $locale = Config::get('app.locale'); + $cookie_locale = Cookie::get('locale'); + // dd($cookie_locale); + if ($cookie_locale && strlen($cookie_locale) == 2) { + $locale = $cookie_locale; + } + App::setLocale($locale); + // Check for UI controller foreach ($packages as $package) { - // Get package namespace $reflector = new \ReflectionClass($package); $namespace = $reflector->getNamespaceName(); + $package = explode('\\', $namespace); + $package = strtolower(array_pop($package)); + // Check for a UI controller $controller = $namespace . "\Ui\UiController"; if (class_exists($controller)) { - // Create controller instance $controller = \App::make($controller); $package_menu = @$controller->menu(); + $translated_menu = []; + + // Translate menu's + foreach ($package_menu as $item) { + $title = trans($package . '::admin.menu_' . $item['slug']); + + if (!empty($title)) { + $item['title'] = $title; + } + + array_push($translated_menu, $item); + } + // Check for added menu items if (!empty($package_menu)) { - $menu = array_merge($menu, $package_menu); + $menu = array_merge($menu, $translated_menu); } // Push for future use @@ -84,13 +110,26 @@ public function __construct() } } + $translated_menu = []; + // Sort menu's usort($menu, function ($a, $b) { return $a['priority'] - $b['priority']; }); + // Translate menu's + foreach ($menu as $item) { + $title = trans('admin.menu_' . $item['slug']); + + if (!empty($title) && $title != 'admin.menu_' . $item['slug']) { + $item['title'] = $title; + } + + array_push($translated_menu, $item); + } + // Share menu with views - \View::share('menu', $menu); + \View::share('menu', $translated_menu); } /** @@ -103,7 +142,6 @@ public function handleRequest($uri) // Check for UI controller foreach ($this->package_controllers as $controller) { - $handled = $controller->handle($uri); // Break and return response if already handled diff --git a/app/Tdt/Core/Validators/CustomValidator.php b/app/Tdt/Core/Validators/CustomValidator.php index abb4a8e9..3e82be82 100644 --- a/app/Tdt/Core/Validators/CustomValidator.php +++ b/app/Tdt/Core/Validators/CustomValidator.php @@ -12,15 +12,25 @@ class CustomValidator extends \Illuminate\Validation\Validator { /** - * Check if the given uri can be resolved by using file_get_contents(). + * Check if the URI can be resolved externally or locally */ public function validateUri($attribute, $value, $parameters) { - try { + if (!filter_var($value, FILTER_VALIDATE_URL) === false) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $value); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - file_get_contents($value); - return true; + $data = curl_exec($ch); + curl_close($ch); + + return !empty($data); + } else { + $data =@ file_get_contents($value); + + return !empty($data); + } } catch (\Exception $ex) { return false; } @@ -33,7 +43,6 @@ public function validateFile($attribute, $value, $parameters) { try { - $handle = fopen($value, 'r'); return $handle; } catch (\Exception $ex) { @@ -46,7 +55,6 @@ public function validateFile($attribute, $value, $parameters) */ public function validateJson($attribute, $value, $parameters) { - try { $data = []; @@ -76,7 +84,6 @@ public function validateJson($attribute, $value, $parameters) public function validateInstalled($attribute, $value, $parameters) { try { - $class_file = app_path() . '/../installed/' . $value; return file_exists($class_file); diff --git a/app/config/app.php b/app/config/app.php index aa24ee48..e2e49cc2 100644 --- a/app/config/app.php +++ b/app/config/app.php @@ -26,7 +26,7 @@ | functionality. | */ - 'version' => '5.6.5', + 'version' => '5.12.0', /* |-------------------------------------------------------------------------- @@ -78,7 +78,7 @@ | */ - 'key' => 'DRxTeqqWmVnqCKNz1dMB3F25jaLIDwCq', + 'key' => 'OQp2ixXYOt2faVaxHr8vInAHCg3uxV67', /* |-------------------------------------------------------------------------- @@ -91,7 +91,6 @@ | */ 'providers' => array( - 'Illuminate\Foundation\Providers\ArtisanServiceProvider', 'Illuminate\Auth\AuthServiceProvider', 'Illuminate\Cache\CacheServiceProvider', @@ -120,6 +119,8 @@ 'Illuminate\Workbench\WorkbenchServiceProvider', 'Cartalyst\Sentry\SentryServiceProvider', 'Tdt\Core\Repositories\DbServiceProvider', + 'Tdt\Core\Analytics\TrackerServiceProvider', + 'Tdt\Input\InputServiceProvider', ), /* @@ -185,7 +186,6 @@ 'URL' => 'Illuminate\Support\Facades\URL', 'Validator' => 'Illuminate\Support\Facades\Validator', 'View' => 'Illuminate\Support\Facades\View', - ), ); diff --git a/app/config/cache.php b/app/config/cache.php index 3884d2b8..38a77973 100644 --- a/app/config/cache.php +++ b/app/config/cache.php @@ -16,7 +16,7 @@ */ 'enabled' => true, - 'driver' => 'file', + 'driver' => 'memcached', /* |-------------------------------------------------------------------------- diff --git a/app/config/tracker.php b/app/config/tracker.php new file mode 100644 index 00000000..74b79fe1 --- /dev/null +++ b/app/config/tracker.php @@ -0,0 +1,5 @@ + '' +); diff --git a/app/database/migrations/2015_07_16_123505_mongo_resource.php b/app/database/migrations/2015_07_16_123505_mongo_resource.php new file mode 100644 index 00000000..06f42815 --- /dev/null +++ b/app/database/migrations/2015_07_16_123505_mongo_resource.php @@ -0,0 +1,38 @@ +increments('id'); + $table->string('mongo_collection', 255); + $table->string('database', 255); + $table->string('username', 255)->nullable(); + $table->string('password', 255)->nullable(); + $table->integer('port'); + $table->string('host', 255); + $table->text('description'); + $table->string('title', 255)->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('mongodefinitions'); + } +} diff --git a/app/database/migrations/2015_08_18_150801_adjust_licenses.php b/app/database/migrations/2015_08_18_150801_adjust_licenses.php new file mode 100644 index 00000000..f7e5d1f2 --- /dev/null +++ b/app/database/migrations/2015_08_18_150801_adjust_licenses.php @@ -0,0 +1,53 @@ +dropColumn('domain_content'); + $table->dropColumn('domain_data'); + $table->dropColumn('domain_software'); + $table->dropColumn('family'); + $table->dropColumn('is_generic'); + $table->dropColumn('is_okd_compliant'); + $table->dropColumn('is_osi_compliant'); + $table->dropColumn('maintainer'); + $table->dropColumn('status'); + $table->dropColumn('url'); + }); + + Schema::table('licenses', function ($table) { + $table->string('url', 255)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('licenses', function ($table) { + $table->boolean('domain_content'); + $table->boolean('domain_data'); + $table->boolean('domain_software'); + $table->string('family', 255)->nullable(); + $table->boolean('is_generic')->nullable(); + $table->boolean('is_okd_compliant'); + $table->boolean('is_osi_compliant'); + $table->string('maintainer', 255)->nullable(); + $table->string('status', 255); + }); + } +} diff --git a/app/database/migrations/2015_09_10_133250_move_map_property.php b/app/database/migrations/2015_09_10_133250_move_map_property.php new file mode 100644 index 00000000..03924be8 --- /dev/null +++ b/app/database/migrations/2015_09_10_133250_move_map_property.php @@ -0,0 +1,57 @@ +dropColumn('map_property'); + }); + + Schema::table('csvdefinitions', function ($table) { + $table->string('map_property', 255)->nullable(); + }); + + Schema::table('shpdefinitions', function ($table) { + $table->string('map_property', 255)->nullable(); + }); + + Schema::table('xlsdefinitions', function ($table) { + $table->string('map_property', 255)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // Drop the title on definitions + Schema::table('definitions', function ($table) { + $table->string('map_property', 255)->nullable(); + }); + + Schema::table('csvdefinitions', function ($table) { + $table->dropColumn('map_property'); + }); + + Schema::table('shpdefinitions', function ($table) { + $table->dropColumn('map_property'); + }); + + Schema::table('xlsdefinitions', function ($table) { + $table->dropColumn('map_property'); + }); + } +} diff --git a/app/database/migrations/2015_10_01_134509_add_dcat_contactpoint.php b/app/database/migrations/2015_10_01_134509_add_dcat_contactpoint.php new file mode 100644 index 00000000..650888b1 --- /dev/null +++ b/app/database/migrations/2015_10_01_134509_add_dcat_contactpoint.php @@ -0,0 +1,32 @@ +string('contact_point', 255); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('definitions', function ($table) { + $table->dropColumn('contact_point'); + }); + } +} diff --git a/app/database/migrations/2015_10_12_133358_add_geo_checkbox_json_xml.php b/app/database/migrations/2015_10_12_133358_add_geo_checkbox_json_xml.php new file mode 100644 index 00000000..fd358a03 --- /dev/null +++ b/app/database/migrations/2015_10_12_133358_add_geo_checkbox_json_xml.php @@ -0,0 +1,39 @@ +boolean('geo_formatted')->nullable(); + }); + + Schema::table('xmldefinitions', function ($table) { + $table->boolean('geo_formatted')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('jsondefinitions', function ($table) { + $table->dropColumn('geo_formatted'); + }); + + Schema::table('xmldefinitions', function ($table) { + $table->dropColumn('geo_formatted'); + }); + } +} diff --git a/app/database/migrations/2015_10_12_204241_add_mysql_description.php b/app/database/migrations/2015_10_12_204241_add_mysql_description.php new file mode 100644 index 00000000..900f461d --- /dev/null +++ b/app/database/migrations/2015_10_12_204241_add_mysql_description.php @@ -0,0 +1,31 @@ +text('description'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('mysqldefinitions', function ($table) { + $table->dropColumn('description'); + }); + } +} diff --git a/app/database/migrations/2015_10_14_151638_es_reader.php b/app/database/migrations/2015_10_14_151638_es_reader.php new file mode 100644 index 00000000..daf3226a --- /dev/null +++ b/app/database/migrations/2015_10_14_151638_es_reader.php @@ -0,0 +1,38 @@ +increments('id', true); + $table->string('host', 255); + $table->integer('port'); + $table->string('es_index', 255); + $table->string('es_type', 255); + $table->string('username', 255)->nullable(); + $table->string('password', 255)->nullable(); + $table->text('description'); + $table->string('title', 255); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('elasticsearchdefinitions'); + } +} diff --git a/app/database/migrations/2015_10_16_134758_add_cache_datatable.php b/app/database/migrations/2015_10_16_134758_add_cache_datatable.php new file mode 100644 index 00000000..b1baa030 --- /dev/null +++ b/app/database/migrations/2015_10_16_134758_add_cache_datatable.php @@ -0,0 +1,32 @@ +string('key')->unique(); + $table->text('value'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('cache'); + } +} diff --git a/app/database/migrations/2015_10_26_114008_merge_json_types.php b/app/database/migrations/2015_10_26_114008_merge_json_types.php new file mode 100644 index 00000000..43b4916e --- /dev/null +++ b/app/database/migrations/2015_10_26_114008_merge_json_types.php @@ -0,0 +1,41 @@ +dropColumn('geo_formatted'); + $table->string('jsontype', 255)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::create('jsonlddefinitions', function ($table) { + $table->increments('id'); + $table->string('uri', 255); + $table->string('description', 255); + $table->timestamps(); + }); + + Schema::table('jsondefinitions', function ($table) { + $table->dropColumn('jsontype'); + $table->boolean('geo_formatted')->nullable(); + }); + } +} diff --git a/app/database/migrations/2015_11_04_125750_geoprojections.php b/app/database/migrations/2015_11_04_125750_geoprojections.php new file mode 100644 index 00000000..0598a00c --- /dev/null +++ b/app/database/migrations/2015_11_04_125750_geoprojections.php @@ -0,0 +1,32 @@ +increments('id'); + $table->string('epsg', 255); + $table->text('projection'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('geoprojections'); + } +} diff --git a/app/database/migrations/2015_11_21_081502_remove_draft.php b/app/database/migrations/2015_11_21_081502_remove_draft.php new file mode 100644 index 00000000..c98f6c1c --- /dev/null +++ b/app/database/migrations/2015_11_21_081502_remove_draft.php @@ -0,0 +1,32 @@ +dropColumn('draft'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('definitions', function ($table) { + $table->boolean('draft'); + }); + } +} diff --git a/app/database/migrations/2015_12_07_165310_use_longtext_cache.php b/app/database/migrations/2015_12_07_165310_use_longtext_cache.php new file mode 100644 index 00000000..670023ef --- /dev/null +++ b/app/database/migrations/2015_12_07_165310_use_longtext_cache.php @@ -0,0 +1,40 @@ +string('key')->unique(); + $table->longText('value'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // Drop to get rid of any cache data as well. + Schema::drop('cache'); + Schema::create('cache', function ($table) { + $table->string('key')->unique(); + $table->text('value'); + $table->integer('expiration'); + }); + } + +} diff --git a/app/database/seeds/DcatSeeder.php b/app/database/seeds/DcatSeeder.php index c306e433..7c086239 100644 --- a/app/database/seeds/DcatSeeder.php +++ b/app/database/seeds/DcatSeeder.php @@ -2,6 +2,7 @@ /** * Seeder for dcat meta-data + * * @copyright (C) 2011, 2014 by OKFN Belgium vzw/asbl * @license AGPLv3 * @author Jan Vansteenlandt @@ -26,6 +27,9 @@ public function run() // Seed the themes $this->seedThemes(); + + // Seed the geoprojections + $this->seedGeoProjections(); } /** @@ -37,41 +41,8 @@ private function seedLicenses() { // Fetch the licenses from the json file $this->command->info('---- DCAT Licenses ----'); - $this->command->info('Trying to fetch the licenses from a local json file.'); - - $licenses = json_decode(file_get_contents(app_path() . '/database/seeds/data/licenses.json')); - - if (!empty($licenses)) { - - $this->command->info('Licenses have been found, deleting the current ones, and replacing them with the new ones.'); - - // Empty the licenses table - $this->command->info('Emptying the current licenses table.'); - - \License::truncate(); - - foreach ($licenses as $license) { - \License::create(array( - 'domain_content' => $license->domain_content, - 'domain_data' => $license->domain_data, - 'domain_software' => $license->domain_software, - 'family' => $license->family, - 'license_id' => $license->license_id, - 'is_generic' => @$license->is_generic, - 'is_okd_compliant' => $license->is_okd_compliant, - 'is_osi_compliant' => $license->is_osi_compliant, - 'maintainer' => $license->maintainer, - 'status' => $license->status, - 'title' => $license->title, - 'url' => $license->url - )); - } - $this->command->info('Added the licenses from a local json file.'); - - } else { - $this->command->info('The licenses from the json file were empty, the old ones will not be replaced.'); - } + \Artisan::call('datatank:licenses'); } /** @@ -90,7 +61,6 @@ private function seedLanguages() $languages = json_decode(file_get_contents(app_path() . '/database/seeds/data/languages.json')); if (!empty($languages)) { - $this->command->info('Languages have been found, deleting the current ones, and replacing them with the new ones.'); $this->command->info('Emptying the current languages table.'); @@ -128,7 +98,6 @@ private function seedThemes() // Try to get the themes from the ns.thedatatank.com (semantic data) try { - $this->command->info('Trying to fetch new themes online.'); $themes_graph = \EasyRdf_Graph::newAndLoad($uri); @@ -146,15 +115,12 @@ private function seedThemes() // Fetch all of the themes foreach ($themes_graph->resourcesMatching('skos:inScheme') as $theme) { - if ($theme->get('skos:inScheme')->getUri() == $uri) { - $theme_uri = $theme->getUri(); $label = $theme->getLiteral('rdfs:label'); if (!empty($label) && !empty($theme_uri)) { - $label = $label->getValue(); $this->command->info('Added ' . $uri . ' with label ' . $label); @@ -175,13 +141,11 @@ private function seedThemes() // If it's not available, get them from a file (json) if (!$themes_fetched) { - $this->command->info('Trying to fetch the themes from the local json file containing a default set of themes.'); $themes = json_decode(file_get_contents(app_path() . '/database/seeds/data/themes.json')); if (!empty($themes)) { - $this->command->info('Found new themes, removing the old ones.'); // Empty the themes table @@ -203,4 +167,31 @@ private function seedThemes() } } } + + private function seedGeoProjections() + { + $this->command->info('---- Geo projections ----'); + + $this->command->info('Fetching geoprojections from the local json file.'); + + $geoprojections = json_decode(file_get_contents(app_path() . '/database/seeds/data/geoprojections.json')); + + if (!empty($geoprojections)) { + $this->command->info('Geoprojections have been found, deleting the current ones, and replacing them with the new ones.'); + + \Geoprojection::truncate(); + + foreach ($geoprojections as $language) { + \Geoprojection::create(array( + 'epsg' => $language->epsg, + 'projection' =>$language->projection, + )); + } + + $this->command->info('Added the geoprojections from a local json file.'); + + } else { + $this->command->info('No languages have not been found, the old ones will not be replaced.'); + } + } } diff --git a/app/database/seeds/DemoDataSeeder.php b/app/database/seeds/DemoDataSeeder.php index 9715cee7..526b31dd 100644 --- a/app/database/seeds/DemoDataSeeder.php +++ b/app/database/seeds/DemoDataSeeder.php @@ -129,7 +129,6 @@ private function seedCsv() $definition->resource_name = $file; $definition->source_id = $csv_def->id; $definition->source_type = 'CsvDefinition'; - $definition->draft = false; $definition->save(); $this->command->info("Published a CSV file with name $file on uri (relative to the root) csv/$file ."); @@ -173,7 +172,6 @@ private function seedXml() $definition->resource_name = $file; $definition->source_id = $xml_def->id; $definition->source_type = 'XmlDefinition'; - $definition->draft = false; $definition->save(); $this->command->info("Published an XML file with file name $file on uri (relative to the root) xml/$file ."); @@ -219,7 +217,6 @@ private function seedJson() $definition->resource_name = $file; $definition->source_id = $json_def->id; $definition->source_type = 'JsonDefinition'; - $definition->draft = false; $definition->save(); $this->command->info("Published a JSON file, $file, on uri (relative to the root) json/$file ."); @@ -313,7 +310,6 @@ private function seedXls() $definition->resource_name = $file; $definition->source_id = $xls_def->id; $definition->source_type = 'XlsDefinition'; - $definition->draft = false; $definition->save(); $this->command->info("Published an XLS file, $file, on uri (relative to the root) xls/$file ."); @@ -381,67 +377,7 @@ private function seedShp() 'property' => 'polyline', ), ), - ), - 'places' => array('file' => 'places', - 'name' => 'places', - 'collection' => 'france', - 'description' => 'Interesting places from "Ile-de-France".', - 'columns' => array( - array( - 'column_name' => 'osm_id', - 'index' => 0, - 'column_name_alias' => 'osm_id', - 'is_pk' => 0 - ), - array( - 'column_name' => 'name', - 'index' => 1, - 'column_name_alias' => 'name', - 'is_pk' => 0 - ), - array( - 'column_name' => 'type', - 'index' => 2, - 'column_name_alias' => 'type', - 'is_pk' => 0 - ), - array( - 'column_name' => 'population', - 'index' => 3, - 'column_name_alias' => 'population', - 'is_pk' => 0 - ), - array( - 'column_name' => 'deleted', - 'index' => 4, - 'column_name_alias' => 'deleted', - 'is_pk' => 0 - ), - array( - 'column_name' => 'x', - 'index' => 5, - 'column_name_alias' => 'x', - 'is_pk' => 0 - ), - array( - 'column_name' => 'y', - 'index' => 6, - 'column_name_alias' => 'y', - 'is_pk' => 0 - ), - ), - 'geo' => array( - array( - 'path' => 'x', - 'property' => 'latitude', - ), - array( - 'path' => 'y', - 'property' => 'longitude', - ), - ), - ), - ); + )); $added = false; @@ -489,7 +425,6 @@ private function seedShp() $definition->resource_name = $info['name']; $definition->source_id = $shp_def->id; $definition->source_type = 'ShpDefinition'; - $definition->draft = false; $definition->save(); $this->command->info("Published a SHP file."); diff --git a/app/database/seeds/GeoSeeder.php b/app/database/seeds/GeoSeeder.php new file mode 100644 index 00000000..430a56b0 --- /dev/null +++ b/app/database/seeds/GeoSeeder.php @@ -0,0 +1,46 @@ +seedGeoprojections(); + } + + /** + * Seed the prefixes table based on the prefixes json file + * + * @return void + */ + private function seedGeoprojections() + { + // Empty the ontology table + \Geoprojection::truncate(); + + // Fetch the ontology from the json file + $geoprojections = json_decode(file_get_contents(app_path() . '/database/seeds/data/geoprojections.json')); + + if (!empty($geoprojections)) { + \Geoprojection::truncate(); + + foreach ($geoprojections as $language) { + \Geoprojection::create(array( + 'epsg' => $language->epsg, + 'projection' =>$language->projection, + )); + } + + $this->command->info("Added the geographical projections."); + } + } +} diff --git a/app/database/seeds/data/geoprojections.json b/app/database/seeds/data/geoprojections.json new file mode 100644 index 00000000..2b54b391 --- /dev/null +++ b/app/database/seeds/data/geoprojections.json @@ -0,0 +1,94 @@ +[ + { + "epsg" : 4326, + "projection" : "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]" + }, + { + "epsg" : 102757, + "projection" : "PROJCS[\"NAD_1983_StatePlane_Wyoming_West_Central_FIPS_4903_Feet\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS_1980\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",1968500],PARAMETER[\"False_Northing\",0],PARAMETER[\"Central_Meridian\",-108.75],PARAMETER[\"Scale_Factor\",0.9999375],PARAMETER[\"Latitude_Of_Origin\",40.5],UNIT[\"Foot_US\",0.30480060960121924],AUTHORITY[\"EPSG\",\"102757\"]]" + }, + { + "epsg" : 102758, + "projection" : "PROJCS[\"NAD_1983_StatePlane_Wyoming_West_FIPS_4904_Feet\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS_1980\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",2624666.666666666],PARAMETER[\"False_Northing\",328083.3333333333],PARAMETER[\"Central_Meridian\",-110.0833333333333],PARAMETER[\"Scale_Factor\",0.9999375],PARAMETER[\"Latitude_Of_Origin\",40.5],UNIT[\"Foot_US\",0.30480060960121924],AUTHORITY[\"EPSG\",\"102758\"]]" + }, + { + "epsg" : 2154, + "projection" : "PROJCS[\"RGF93 / Lambert-93\",GEOGCS[\"RGF93\",DATUM[\"Reseau_Geodesique_Francais_1993\",SPHEROID[\"GRS 1980\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"7019\"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",\"6171\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4171\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Lambert_Conformal_Conic_2SP\"],PARAMETER[\"standard_parallel_1\",49],PARAMETER[\"standard_parallel_2\",44],PARAMETER[\"latitude_of_origin\",46.5],PARAMETER[\"central_meridian\",3],PARAMETER[\"false_easting\",700000],PARAMETER[\"false_northing\",6600000],AUTHORITY[\"EPSG\",\"2154\"],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]" + }, + { + "epsg" : 21781, + "projection" : "PROJCS[\"CH1903 / LV03\",GEOGCS[\"CH1903\",DATUM[\"CH1903\",SPHEROID[\"Bessel 1841\",6377397.155,299.1528128,AUTHORITY[\"EPSG\",\"7004\"]],TOWGS84[674.374,15.056,405.346,0,0,0,0],AUTHORITY[\"EPSG\",\"6149\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4149\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Hotine_Oblique_Mercator\"],PARAMETER[\"latitude_of_center\",46.95240555555556],PARAMETER[\"longitude_of_center\",7.439583333333333],PARAMETER[\"azimuth\",90],PARAMETER[\"rectified_grid_angle\",90],PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",600000],PARAMETER[\"false_northing\",200000],AUTHORITY[\"EPSG\",\"21781\"],AXIS[\"Y\",EAST],AXIS[\"X\",NORTH]]" + }, + { + "epsg" : 25832, + "projection" : "PROJCS[\"ETRS89 / UTM zone 32N\",GEOGCS[\"ETRS89\",DATUM[\"European_Terrestrial_Reference_System_1989\",SPHEROID[\"GRS 1980\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6258\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4258\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",9],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"25832\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]" + }, + { + "epsg" : 25833, + "projection" : "PROJCS[\"ETRS89 / UTM zone 33N\",GEOGCS[\"ETRS89\",DATUM[\"European_Terrestrial_Reference_System_1989\",SPHEROID[\"GRS 1980\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6258\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4258\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",15],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"25833\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]" + }, + { + "epsg" : 26591, + "projection" : "PROJCS[\"Monte Mario (Rome) / Italy zone 1 (deprecated)\",GEOGCS[\"Monte Mario (Rome)\",DATUM[\"Monte_Mario_Rome\",SPHEROID[\"International 1924\",6378388,297,AUTHORITY[\"EPSG\",\"7022\"]],AUTHORITY[\"EPSG\",\"6806\"]],PRIMEM[\"Rome\",12.45233333333333,AUTHORITY[\"EPSG\",\"8906\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4806\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-3.45233333333333],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",1500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"26591\"],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]" + }, + { + "epsg" : 26912, + "projection" : "PROJCS[\"NAD83 / UTM zone 12N\",GEOGCS[\"NAD83\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS 1980\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6269\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4269\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-111],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"26912\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]" + }, + { + "epsg" : 27200, + "projection" : "PROJCS[\"NZGD49 / New Zealand Map Grid\",GEOGCS[\"NZGD49\",DATUM[\"New_Zealand_Geodetic_Datum_1949\",SPHEROID[\"International 1924\",6378388,297,AUTHORITY[\"EPSG\",\"7022\"]],TOWGS84[59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993],AUTHORITY[\"EPSG\",\"6272\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4272\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"New_Zealand_Map_Grid\"],PARAMETER[\"latitude_of_origin\",-41],PARAMETER[\"central_meridian\",173],PARAMETER[\"false_easting\",2510000],PARAMETER[\"false_northing\",6023150],AUTHORITY[\"EPSG\",\"27200\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]" + }, + { + "epsg" : 27563, + "projection" : "PROJCS[\"NTF (Paris) / Lambert Sud France\",GEOGCS[\"NTF (Paris)\",DATUM[\"Nouvelle_Triangulation_Francaise_Paris\",SPHEROID[\"Clarke 1880 (IGN)\",6378249.2,293.4660212936269,AUTHORITY[\"EPSG\",\"7011\"]],TOWGS84[-168,-60,320,0,0,0,0],AUTHORITY[\"EPSG\",\"6807\"]],PRIMEM[\"Paris\",2.33722917,AUTHORITY[\"EPSG\",\"8903\"]],UNIT[\"grad\",0.01570796326794897,AUTHORITY[\"EPSG\",\"9105\"]],AUTHORITY[\"EPSG\",\"4807\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Lambert_Conformal_Conic_1SP\"],PARAMETER[\"latitude_of_origin\",49],PARAMETER[\"central_meridian\",0],PARAMETER[\"scale_factor\",0.999877499],PARAMETER[\"false_easting\",600000],PARAMETER[\"false_northing\",200000],AUTHORITY[\"EPSG\",\"27563\"],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]" + }, + { + "epsg" : 27571, + "projection" : "PROJCS[\"NTF (Paris) / Lambert zone I\",GEOGCS[\"NTF (Paris)\",DATUM[\"Nouvelle_Triangulation_Francaise_Paris\",SPHEROID[\"Clarke 1880 (IGN)\",6378249.2,293.4660212936269,AUTHORITY[\"EPSG\",\"7011\"]],TOWGS84[-168,-60,320,0,0,0,0],AUTHORITY[\"EPSG\",\"6807\"]],PRIMEM[\"Paris\",2.33722917,AUTHORITY[\"EPSG\",\"8903\"]],UNIT[\"grad\",0.01570796326794897,AUTHORITY[\"EPSG\",\"9105\"]],AUTHORITY[\"EPSG\",\"4807\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Lambert_Conformal_Conic_1SP\"],PARAMETER[\"latitude_of_origin\",55],PARAMETER[\"central_meridian\",0],PARAMETER[\"scale_factor\",0.999877341],PARAMETER[\"false_easting\",600000],PARAMETER[\"false_northing\",1200000],AUTHORITY[\"EPSG\",\"27571\"],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]" + }, + { + "epsg" : 31258, + "projection" : "PROJCS[\"MGI / Austria GK M31\",GEOGCS[\"MGI\",DATUM[\"Militar_Geographische_Institute\",SPHEROID[\"Bessel 1841\",6377397.155,299.1528128,AUTHORITY[\"EPSG\",\"7004\"]],TOWGS84[577.326,90.129,463.919,5.137,1.474,5.297,2.4232],AUTHORITY[\"EPSG\",\"6312\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AUTHORITY[\"EPSG\",\"4312\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",13.33333333333333],PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",450000],PARAMETER[\"false_northing\",-5000000],AUTHORITY[\"EPSG\",\"31258\"],AXIS[\"Y\",EAST],AXIS[\"X\",NORTH]]" + }, + { + "epsg" : 31370, + "projection" : "PROJCS[\"Belge 1972 / Belgian Lambert 72\",GEOGCS[\"Belge 1972\",DATUM[\"Reseau_National_Belge_1972\",SPHEROID[\"International 1924\",6378388,297,AUTHORITY[\"EPSG\",\"7022\"]],TOWGS84[106.869,-52.2978,103.724,-0.33657,0.456955,-1.84218,1],AUTHORITY[\"EPSG\",\"6313\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4313\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Lambert_Conformal_Conic_2SP\"],PARAMETER[\"standard_parallel_1\",51.16666723333333],PARAMETER[\"standard_parallel_2\",49.8333339],PARAMETER[\"latitude_of_origin\",90],PARAMETER[\"central_meridian\",4.367486666666666],PARAMETER[\"false_easting\",150000.013],PARAMETER[\"false_northing\",5400088.438],AUTHORITY[\"EPSG\",\"31370\"],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]" + }, + { + "epsg" : 31467, + "projection" : "PROJCS[\"DHDN / Gauss-Kruger zone 3\",GEOGCS[\"DHDN\",DATUM[\"Deutsches_Hauptdreiecksnetz\",SPHEROID[\"Bessel 1841\",6377397.155,299.1528128,AUTHORITY[\"EPSG\",\"7004\"]],AUTHORITY[\"EPSG\",\"6314\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4314\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",9],PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",3500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"31467\"],AXIS[\"Y\",EAST],AXIS[\"X\",NORTH]]" + }, + { + "epsg" : 31468, + "projection" : "PROJCS[\"DHDN / Gauss-Kruger zone 4\",GEOGCS[\"DHDN\",DATUM[\"Deutsches_Hauptdreiecksnetz\",SPHEROID[\"Bessel 1841\",6377397.155,299.1528128,AUTHORITY[\"EPSG\",\"7004\"]],AUTHORITY[\"EPSG\",\"6314\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4314\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",12],PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",4500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"31468\"],AXIS[\"Y\",EAST],AXIS[\"X\",NORTH]]" + }, + { + "epsg" : 3785, + "projection" : "PROJCS[\"Popular Visualisation CRS / Mercator\",GEOGCS[\"Popular Visualisation CRS\",DATUM[\"Popular_Visualisation_Datum\",SPHEROID[\"Popular Visualisation Sphere\",6378137,0,AUTHORITY[\"EPSG\",\"7059\"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",\"6055\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4055\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Mercator_1SP\"],PARAMETER[\"central_meridian\",0],PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"3785\"],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]" + }, + { + "epsg" : 4139, + "projection" : "GEOGCS[\"Puerto Rico\",DATUM[\"Puerto_Rico\",SPHEROID[\"Clarke 1866\",6378206.4,294.9786982138982,AUTHORITY[\"EPSG\",\"7008\"]],TOWGS84[11,72,-101,0,0,0,0],AUTHORITY[\"EPSG\",\"6139\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4139\"]]" + }, + { + "epsg" : 4181, + "projection" : "GEOGCS[\"Luxembourg 1930\",DATUM[\"Luxembourg_1930\",SPHEROID[\"International 1924\",6378388,297,AUTHORITY[\"EPSG\",\"7022\"]],TOWGS84[-193,13.7,-39.3,-0.41,-2.933,2.688,0.43],AUTHORITY[\"EPSG\",\"6181\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4181\"]]" + }, + { + "epsg" : 42304, + "projection" : "PROJCS[\"NAD83 / NRCan LCC Canada\",GEOGCS[\"NAD83\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS_1980\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"Decimal_Degree\",0.0174532925199433]],PROJECTION[\"Lambert_Conformal_Conic_2SP\"],PARAMETER[\"central_meridian\",-95.0],PARAMETER[\"latitude_of_origin\",49.0],PARAMETER[\"standard_parallel_1\",49.0],PARAMETER[\"standard_parallel_2\",77.0],PARAMETER[\"false_easting\",0.0],PARAMETER[\"false_northing\",0.0],UNIT[\"Meter\",1],AUTHORITY[\"EPSG\",\"42304\"]]" + }, + { + "epsg" : 4269, + "projection" : "GEOGCS[\"NAD83\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS 1980\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6269\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4269\"]]" + }, + { + "epsg" : 4272, + "projection" : "GEOGCS[\"NZGD49\",DATUM[\"New_Zealand_Geodetic_Datum_1949\",SPHEROID[\"International 1924\",6378388,297,AUTHORITY[\"EPSG\",\"7022\"]],TOWGS84[59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993],AUTHORITY[\"EPSG\",\"6272\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4272\"]]" + }, + { + "epsg" : 4302, + "projection" : "GEOGCS[\"Trinidad 1903\",DATUM[\"Trinidad_1903\",SPHEROID[\"Clarke 1858\",6378293.645208759,294.2606763692654,AUTHORITY[\"EPSG\",\"7007\"]],AUTHORITY[\"EPSG\",\"6302\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4302\"]]" + } +] \ No newline at end of file diff --git a/app/database/seeds/data/licenses.json b/app/database/seeds/data/licenses.json index c08edc67..650e4d5a 100644 --- a/app/database/seeds/data/licenses.json +++ b/app/database/seeds/data/licenses.json @@ -104,6 +104,103 @@ "title": "GNU Free Documentation License", "url": "http://www.opendefinition.org/licenses/gfdl" }, + { + "domain_content": true, + "domain_data": false, + "domain_software": false, + "family": "", + "license_id": "gfdl", + "is_okd_compliant": true, + "is_osi_compliant": false, + "maintainer": "", + "status": "active", + "title": "Modellicentie 2 - Gratis Open Data Licentie - v1.0", + "url": "http://opendataforum.info/Docs/LICENTIES_2014/Modellicentie 2 - Gratis Open Data Licentie - v1.0.htm" + }, + { + "domain_content": true, + "domain_data": false, + "domain_software": false, + "family": "", + "license_id": "other-open", + "is_generic": true, + "is_okd_compliant": true, + "is_osi_compliant": false, + "maintainer": "", + "status": "active", + "title": "CC0 1.0 Universal", + "url": "http://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + { + "domain_content": true, + "domain_data": false, + "domain_software": false, + "family": "", + "license_id": "other-open", + "is_generic": true, + "is_okd_compliant": true, + "is_osi_compliant": false, + "maintainer": "", + "status": "active", + "title": "Modellicentie 2 - Gratis Open Data Licentie - v1.2 Universal", + "url": "http://id.vlaanderen.be/licentie/gratis-open-data-licentie#id" + }, + { + "domain_content": true, + "domain_data": false, + "domain_software": false, + "family": "", + "license_id": "other-open", + "is_generic": true, + "is_okd_compliant": true, + "is_osi_compliant": false, + "maintainer": "", + "status": "active", + "title": "Modellicentie 4a+4b - Gratis Open Data Licentie voor Niet-Commercieel Hergebruik en Open Data Licentie voor Commercieel Hergebruik - v1.0", + "url": "http://opendataforum.info/Docs/LICENTIES_2014/Modellicentie 4a 4b - Gratis Open Data Licentie voor Niet-Commercieel Hergebruik en OpenData Licentie voor Commercieel Hergebruik - v1.0.htm" + }, + { + "domain_content": true, + "domain_data": false, + "domain_software": false, + "family": "", + "license_id": "other-open", + "is_generic": true, + "is_okd_compliant": true, + "is_osi_compliant": false, + "maintainer": "", + "status": "active", + "title": "Modellicentie 4a+4b - Gratis Open Data Licentie voor Niet-Commercieel Hergebruik en Open Data Licentie voor Commercieel Hergebruik - v1.2", + "url": "http://opendataforum.info/Docs/licenties/BV.htm" + }, + { + "domain_content": true, + "domain_data": false, + "domain_software": false, + "family": "", + "license_id": "other-open", + "is_generic": true, + "is_okd_compliant": true, + "is_osi_compliant": false, + "maintainer": "", + "status": "active", + "title": "Modellicentie 3 - Open Data Licentie tegen Billijke Vergoeding - v1.0", + "url": "http://opendataforum.info/Docs/LICENTIES_2014/Modellicentie%203%20-%20Open%20Data%20Licentie%20tegen%20Billijke%20Vergoeding%20-%20v1.0.htm" + }, + { + "domain_content": true, + "domain_data": false, + "domain_software": false, + "family": "", + "license_id": "other-open", + "is_generic": true, + "is_okd_compliant": true, + "is_osi_compliant": false, + "maintainer": "", + "status": "active", + "title": "Modellicentie 3 - Open Data Licentie tegen Billijke Vergoeding - v1.2", + "url": "http://id.vlaanderen.be/licentie/open-data-licentie-tegen-billijke-vergoeding#id" + }, { "domain_content": true, "domain_data": false, diff --git a/app/lang/en/admin.php b/app/lang/en/admin.php new file mode 100644 index 00000000..85de6f85 --- /dev/null +++ b/app/lang/en/admin.php @@ -0,0 +1,67 @@ + "Add a dataset", + "build_identifier" => "Create a publishing URI", + "collection" => "Collection", + "collection_help" => "A single or multi slug part of the publishing URI that helps categorize this dataset e.g. forests, or forests/2015", + "resource_name" => "Resource name", + "resource_name_help" => "The specific identification of the dataset in the publishing URI e.g. treecount", + "required_parameters" => "Required parameters", + "submit_issue" => "Submit an issue", + "visit_site" => "Visit our website", + "identifier" => "Identifier", + "build_identifier" => "Build the dataset's identifier", + "select_type" => "Select the dataset's type and fill out the metadata", + "collection" => "Collection", + "collection_help" => "Pick a collection to add the dataset to, add a forward slash to create a subcollection", + "resource_name" => "Resource name", + "type" => "Type", + "optional_parameters" => "Optional parameters", + "caching" => "Caching", + "cache_for" => "Cache for", + "minute" => "minute(s)", + "cache_help" => "How long should this dataset be cached? Fill out '0' or '-1' to disable caching for this resource (not recommended).", + "dcat_header" => "Describe your data", + "edit_dataset" => "Edit a dataset", + "parameters" => "Parameters", + "source_type" => "Source type", + "header_dataset_panel" => "Manage your data", + "add_button" => "Add", + "view_data" => "Data", + "view_definition" => "Definition", + "no_datasets_message" => "This datatank is hungry for data, no datasets were added yet.", + "no_datasets_filter_message" => "No dataset(s) found with the filter", + "header_group_panel" => "Manage your groups and permissions", + "rename" => "Rename", + "edit" => "Edit", + "view" => "View", + "permissions" => "Permissions", + "all" => "All", + "save_permissions" => "Save permissions", + "add_group" => "Add a group", + "delete_group" => "Delete this group", + "name" => "Name", + "cancel" => "Cancel", + "rename_group" => "Rename a group", + "save" => "Save", + "header_user_panel" => "Manage your users", + "user_you" => "you", + "add_user" => "Add user", + "username" => "Username", + "group" => "Group", + "edit_user" => "Edit user", + "password" => "Password", + "password_help" => "Leave blank if you want to keep the current password.", + "sign_out" => "Sign out", + "admin_header" => "Datasets", + "sign_in_header" => "Please sign in", + "sign_in" => "Sign in", + "menu_settings" => "General", + "menu_datasets" => "Datasets", + "menu_users" => "Users", + "menu_groups" => "Groups" +); diff --git a/app/lang/en/datasets.php b/app/lang/en/datasets.php new file mode 100644 index 00000000..15122221 --- /dev/null +++ b/app/lang/en/datasets.php @@ -0,0 +1,16 @@ + "Collections & datasets", + "filter" => "Filter", + "no_datasets_filter_message" => "No collection(s) or dataset(s) found with the filter", + "view_json" => "View as JSON", + "collection" => "Collection", + "collection_description" => "This URI is a collection, and can contain datasets and other collections.", + "formats" => "Formats", + "description" => "Description", + "source_type" => "Source type", + "license" => "License", + "no_datasets_message" => "This datatank is hungry for data, no datasets were added yet.", + "search_datasets" => "Search for datasets", +); diff --git a/app/lang/en/errors.php b/app/lang/en/errors.php new file mode 100644 index 00000000..261647d8 --- /dev/null +++ b/app/lang/en/errors.php @@ -0,0 +1,12 @@ + "Oops, something went wrong.", + '403' => "Oops, it seems you don't have enough rights to access this!", + '404' => 'Oops, there is nothing here!', + '500' => 'Oops, we did something wrong!', + 'contact_us' => 'If this error persists, get in touch with us!', + 'submit_issue' => 'Submit an issue to the repository.', + 'visit_site' => 'Visit our website', + 'message' => 'Message', +); diff --git a/app/lang/en/htmlview.php b/app/lang/en/htmlview.php new file mode 100644 index 00000000..82bce36f --- /dev/null +++ b/app/lang/en/htmlview.php @@ -0,0 +1,11 @@ + "Formats", + "description" => "Description", + "source_type" => "Source type", + "license" => "License", + "contact" => "Contact", + "publisher" => "Publisher", + "keywords" => "Keywords", +]; diff --git a/app/lang/en/pagination.php b/app/lang/en/pagination.php index eb9be3ba..63979401 100644 --- a/app/lang/en/pagination.php +++ b/app/lang/en/pagination.php @@ -1,4 +1,4 @@ - 'URI', + 'csv_uri_desc' => 'The location of the CSV file, either a URL or a local file location.', + 'csv_title' => 'Title', + 'csv_title_desc' => 'A name given to the resource.', + 'csv_description' => 'Description', + 'csv_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'csv_delimiter' => 'Delimiter', + 'csv_delimiter_desc' => 'The delimiter of the CSV file.', + 'csv_has_header_row' => 'Header row', + 'csv_has_header_row_desc' => 'Boolean parameter defining if the CSV file contains a header row that contains the column names.', + 'csv_start_row' => 'Start row', + 'csv_start_row_desc' => 'Defines the row at which the data (and header row if present) starts in the file.', + 'csv_pk' => 'Primary key', + 'csv_pk_desc' => 'This is a shortcut to define a primary key of this dataset. + The value must be the index of the column you want each row to be mapped on. + The value of the selected column will then act as a unique key on which data will be mapped.', + 'csv_map_property' => 'Map property', + 'csv_map_property_desc' => 'The property (e.g. column name) of the dataset that will be shown when a map visualization is applicable.', + 'definition_date' => 'Date', + 'definition_date_desc' => 'A point or period of time associated with an event in the lifecycle of the resource. Best practise is to use the ISO 8601 scheme.', + 'definition_language' => 'Language', + 'definition_language_desc' => 'A language of the resource.', + 'definition_rights' => 'Rights', + 'definition_rights_description' => 'Information about rights held in and over the resource.', + 'definition_theme' => 'Theme', + 'definition_theme_description' => 'The theme or category that the dataset belongs to.', + 'definition_cache_minutes' => 'Cache', + 'definition_cache_minutes_desc' => 'How long this resource should be cached (in minutes).', + 'definition_draft' => 'Draft', + 'definition_draft_desc' => 'Draft definitions are not shown to the public when created, however the URI space they take is reserved.', + 'definition_publisher_uri' => 'Publisher URI', + 'definition_publisher_uri_desc' => 'The URI of the entity responsible for publishing the dataset (e.g. http://gov.be). ', + 'definition_publisher_name' => 'Publisher name', + 'definition_publisher_name_desc' => 'The name of the entity responsible for publishing the dataset.', + 'definition_keywords' => 'Keywords', + 'definition_keywords_desc' => 'A comma separated list of keywords regarding the dataset.', + 'definition_contact_point' => 'Contact point', + 'definition_contact_point_desc' => 'A link on which people can provide feedback or flag errors.', + 'definition_rights' => 'License', + 'definition_rights_desc' => 'The license associated with the data.', + 'definition_theme' => 'Theme', + 'definition_theme_desc' => 'The theme associated with the data.', + 'json_uri' => 'URI', + 'json_uri_desc' => 'The location of the JSON file, this should either be a URL or a local file location.', + 'json_title' => 'Title', + 'json_title_desc' => 'A name given to the resource.', + 'json_description' => 'Description', + 'json_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'json_jsontype' => 'JSON type', + 'json_jsontype_desc' => 'Indicates if the JSON document is a plain one or has more specified structure.', + 'mongo_description' => 'Description', + 'mongo_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'mongo_host' => 'Host', + 'mongo_host_desc' => 'The host of the MongoDB database.', + 'mongo_database' => 'Database', + 'mongo_database_desc' => 'The name of the database where the collection, that needs to be published, resides.', + 'mongo_mongo_collection' => 'Collection', + 'mongo_mongo_collection_desc' => 'The name of the MongoDB collection.', + 'mongo_port' => 'Port', + 'mongo_port_desc' => 'The port of the MongoDB database where a connection can be set up.', + 'mongo_username' => 'Username', + 'mongo_username_desc' => 'A username that has read permissions on the provided collection. Safety first, make sure the user only has read permissions.', + 'mongo_password' => 'Password', + 'mongo_password_desc' => 'The password for the user that has read permissions.', + 'mysql_host' => 'Host', + 'mysql_host_desc' => 'The host of the MySQL database.', + 'mysql_port' => 'Port', + 'mysql_port_desc' => 'The port of the MySQL database where a connection can be made to.', + 'mysql_database' => 'Database', + 'mysql_database_desc' => 'The name of the database where the datatable, that needs to be published, resides.', + 'mysql_username' => 'Username', + 'mysql_username_desc' => 'A username that has read permissions on the provided datatable. Safety first, make sure the user only has read permissions.', + 'mysql_password' => 'Password', + 'mysql_password_desc' => 'The password for the user that has read permissions.', + 'mysql_collation' => 'Collation', + 'mysql_collation_desc' => 'The collation of the datatable.', + 'mysql_pk' => 'Primary key', + 'mysql_pk_desc' => 'This is a shortcut to define a primary key of this dataset. + The value must be the index of the column you want each row to be mapped on. + The pk property will never explicitly appear in the definition, but will manifest itself as part of a column property.', + 'mysql_query' => 'Query', + 'mysql_query_desc' => 'The query of which the results will be published as open data.', + 'mysql_map_property' => 'Map property', + 'mysql_map_property_desc' => 'The property (e.g. column name) of the dataset that will be shown when a map visualization is applicable.', + 'mysql_description' => 'Description', + 'mysql_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'rdf_uri' => 'URI', + 'rdf_uri_desc' => 'The URI of the RDF file.', + 'rdf_title' => 'Title', + 'rdf_title_desc' => 'A name given to the resource.', + 'rdf_description' => 'Description', + 'rdf_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'rdf_format' => 'Format', + 'rdf_format_desc' => 'The format of your RDF content, Turtle, XML, ...', + 'shp_uri' => 'URI', + 'shp_uri_desc' => 'The location of the SHP file, either a URL or a local file location.', + 'shp_title' => 'Title', + 'shp_title_desc' => 'A name given to the resource.', + 'shp_description' => 'Description', + 'shp_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'shp_epsg' => 'EPSG', + 'shp_epsg_desc' => 'This parameter holds the EPSG code in which the geometric properties in the shape file are encoded.', + 'shp_map_property' => 'Map property', + 'shp_map_property_desc' => 'A common property that uniquely identifies an object.', + 'sparql_endpoint' => 'SPARQL endpoint', + 'sparql_endpoint_desc' => 'The URI of the SPARQL end-point (e.g. http://foobar:8890/sparql-auth).', + 'sparql_title' => 'Title', + 'sparql_title_desc' => 'A name given to the resource.', + 'sparql_description' => 'Description', + 'sparql_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'sparql_query' => 'SPARQL query', + 'sparql_query_desc' => 'The query to be executed.', + 'sparql_endpoint_user' => 'SPARQL endpoint user', + 'sparql_endpoint_user_desc' => 'Username of the user that has sufficient rights to query the sparql endpoint.', + 'sparql_endpoint_password' => "SPARQL endpoint user's password", + 'sparql_endpoint_password_desc' => 'Password of the provided user to query a sparql endpoint.', + 'xls_uri' => 'URI', + 'xls_uri_desc' => 'The location of the XLS file, either a URL or a local file location.', + 'xls_title' => 'Title', + 'xls_title_desc' => 'A name given to the resource.', + 'xls_description' => 'Description', + 'xls_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'xls_sheet' => 'XLS sheet', + 'xls_sheet_desc' => 'The sheet name in which the tabular data resides.', + 'xls_has_header_row' => 'Header row', + 'xls_has_header_row_desc' => 'Boolean parameter defining if the XLS file contains a header row that contains the column names.', + 'xls_start_row' => 'Start row', + 'xls_start_row_desc' => 'Defines the row at which the data (and header row if present) starts in the file.', + 'xls_pk' => 'Primary key', + 'xls_pk_desc' => 'This is a shortcut to define a primary key of this dataset. The value must be the index of the column you want each row to be mapped on. The pk property will never explicitly appear in the definition, but will manifest itself as part of a column property.', + 'xls_map_property' => 'Map property', + 'xls_map_property_desc' => 'The property (e.g. column name) of the dataset that will be shown when a map visualization is applicable.', + 'xml_uri' => 'URI', + 'xml_uri_desc' => 'The location of the XML file, this should either be a URL or a local file location.', + 'xml_title' => 'Title', + 'xml_title_desc' => 'A name given to the resource.', + 'xml_description' => 'Description', + 'xml_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'xml_geo_formatted' => 'KML', + 'xml_geo_formatted_desc' => 'Is the XML document a KML document.', + 'installed_class' => 'Class', + 'installed_class_desc' => 'The name of the class that holds the data publishing functionalities.', + 'installed_path' => 'Class path', + 'installed_path_desc' => 'The location of the class file, relative from the "/installed" folder.', + 'installed_title' => 'Title', + 'installed_title_desc' => 'A name given to the resource.', + 'installed_description' => 'Description', + 'installed_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'elasticsearch_description' => 'Description', + 'elasticsearch_description_desc' => 'The descriptive or informational string that provides some context for you published dataset.', + 'elasticsearch_host' => 'Host', + 'elasticsearch_host_desc' => 'The host of the Elasticsearch.', + 'elasticsearch_es_type' => 'Type', + 'elasticsearch_es_type_desc' => 'The type of data that needs to published from the index', + 'elasticsearch_es_index' => 'Index', + 'elasticsearch_es_index_desc' => 'The name of the Elasticsearch index', + 'elasticsearch_port' => 'Port', + 'elasticsearch_port_desc' => 'The port of the Elasticsearch where a connection can be set up.', + 'elasticsearch_username' => 'Username', + 'elasticsearch_username_desc' => 'A username that has read permissions on the provided index. Safety first, make sure the user only has read permissions.', + 'elasticsearch_password' => 'Password', + 'elasticsearch_password_desc' => 'The password for the user that has read permissions.', +); diff --git a/app/lang/en/settings.php b/app/lang/en/settings.php new file mode 100644 index 00000000..f49ec3e7 --- /dev/null +++ b/app/lang/en/settings.php @@ -0,0 +1,16 @@ + "General settings", + "title" => "Title", + "title_help" => "The name given to the catalog of datasets", + "description" => "Description", + "description_help" => "Description of the general theme of the datasets", + "publisher" => "Publisher", + "publisher_help" => "The name of the entity responsible for publishing the catalog", + "publisher_uri_help" => "The URI of the entity responsible for publishing the catalog", + "language" => "Language", + "language_help" => "The language of the majority of datasets", + "dcat_link" => "DCAT-AP feed", + "save" => "Save", +); diff --git a/app/lang/fr/admin.php b/app/lang/fr/admin.php new file mode 100644 index 00000000..342dd98d --- /dev/null +++ b/app/lang/fr/admin.php @@ -0,0 +1,63 @@ + "Ajouter un jeu de données", + "required_parameters" => "Paramètres requis", + "build_identifier" => "Construire un URI pour le jeu de données", + "select_type" => "Choisir une source des données et remplir les méta-données", + "collection" => "Collection", + "submit_issue" => "Envoyer un problème", + "visit_site" => "Visitez notre site Internet", + "collection_help" => "Un nom collectif qui categorise le dataset (e.g. forets ou forets/2015)", + "resource_name" => "Nom du dataset", + "resource_name_help" => "Le nom specific pour le jeu de données e.g. noyers", + "identifier" => "Identificateur", + "type" => "Type", + "optional_parameters" => "Paramètres optionels", + "caching" => "La mise en cache", + "cache_for" => "Cache pour", + "minute" => "minute(s)", + "cache_help" => "Depands combien de minutes est-ce que ce jeu de donnée doit être mis en cache? Entrez 0 ou -1 pour ignorer la mise en cache.", + "dcat_header" => "Décrivez votre jeu de données", + "edit_dataset" => "Modifier votre jeu de données", + "parameters" => "Paramètres", + "source_type" => "type de source", + "header_dataset_panel" => "Gérer votre jeux de données", + "add_button" => "Ajouter", + "view_data" => "Data", + "view_definition" => "Définition", + "no_datasets_message" => "Ce datatank n'a pas de jeux de données.", + "no_datasets_filter_message" => "Nous n'avons pas trouvés des jeux de données avec le filtre.", + "header_group_panel" => "Gérer votre groupes et permissions", + "rename" => "Modifier le nom", + "edit" => "Modifier", + "view" => "Regarder", + "permissions" => "Permissions", + "all" => "Tout", + "save_permissions" => "Sauver les permissions", + "add_group" => "Ajouter un group", + "name" => "Nom", + "cancel" => "Annuler", + "rename_group" => "Changer le nom du group.", + "save" => "Sauver", + "header_user_panel" => "Gérer vos utilisateurs", + "user_you" => "vous-même", + "add_user" => "Ajouter un utilisateur", + "username" => "nom d'utilisateur", + "group" => "Group", + "edit_user" => "Modifier un utilisateur", + "password" => "Mot de passe", + "password_help" => "Laissez ce champ vide pour maintenir votre mot de passe actuel.", + "sign_out" => "Déconnecter", + "admin" => "Admin", + "sign_in_header" => "Connectez vous s'il vous plait", + "sign_in" => "Connectez-vous", + "admin_header" => "Jeux de données", + "menu_settings" => "Général", + "menu_datasets" => "Jeux de données", + "menu_users" => "Utilisateurs", + "menu_groups" => "Groupes" +); diff --git a/app/lang/fr/datasets.php b/app/lang/fr/datasets.php new file mode 100644 index 00000000..e89d11cb --- /dev/null +++ b/app/lang/fr/datasets.php @@ -0,0 +1,15 @@ + "Collections & jeux de données", + "filter" => "Filtre", + "nothing_found_filter" => "Nous n'avons pas trouvés des jeux de données avec le filtre.", + "view_json" => "Voir comme JSON", + "collection" => "Collection", + "collection_description" => "Ce URI est une collection qui peut avoir d'autres collections ou jeux de données.", + "formats" => "Formats", + "description" => "Description", + "source_type" => "Type de source", + "license" => "Permis", + "search_datasets" => "Trouver un jeu de données", +); diff --git a/app/lang/fr/errors.php b/app/lang/fr/errors.php new file mode 100644 index 00000000..b83c5cbc --- /dev/null +++ b/app/lang/fr/errors.php @@ -0,0 +1,11 @@ + "Oops, quelque chose a mal tourné.", + "403" => "Oops, vous disposez de privilèges suffisants pour effectuer cette action.", + "404" => "Oops, il semble que rien ne sera!", + "500" => "Oops, quelque chose allait mal!", + "contact_us" => "Si cette erreur persiste, s'il vous plaît contactez-nous!", + "submit_issue" => "Créer un nouveau rapport sur notre github.", + "visit_site" => "Visitez notre site web.", +); diff --git a/app/lang/fr/htmlview.php b/app/lang/fr/htmlview.php new file mode 100644 index 00000000..32672589 --- /dev/null +++ b/app/lang/fr/htmlview.php @@ -0,0 +1,11 @@ + "Formats", + "description" => "Description", + "source_type" => "Type de ressource", + "license" => "Licence", + "contact" => "Contact", + "publisher" => "Editeur", + "keywords" => "mot-clés", +]; diff --git a/app/lang/fr/parameters.php b/app/lang/fr/parameters.php new file mode 100644 index 00000000..b2ee8d5e --- /dev/null +++ b/app/lang/fr/parameters.php @@ -0,0 +1,170 @@ + 'URI', + 'csv_uri_desc' => "L'emplacement du fichier CSV, une URL ou un emplacement de fichier local.", + 'csv_title' => 'Titre', + 'csv_title_desc' => 'Un nom donné à la ressource.', + 'csv_description' => 'Description', + 'csv_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'csv_delimiter' => 'Séparateur', + 'csv_delimiter_desc' => 'Le séparateur du fichier CSV.', + 'csv_has_header_row' => 'Tête de rang', + 'csv_has_header_row_desc' => "Un paramètre booléen qui définit si le fichier CSV contient une ligne d'en-tête de cette colonne contient les noms.", + 'csv_start_row' => 'Ligne de départ', + 'csv_start_row_desc' => 'Définit la rangée à laquelle les données (et la ligne de titre si présent) commence dans le fichier.', + 'csv_pk' => 'Clé primaire', + 'csv_pk_desc' => "Ceci est un raccourci pour définir une clé primaire de cet ensemble de données. +                                 La valeur doit être l'indice de la colonne que vous voulez chaque rangée pour être plaqué. +                                 La propriété sélectionnée sera utilisée comme identifiant unique sur les objets qui seront mises en correspondance avec le format de sortie", + 'csv_map_property' => 'Carte propriété', + 'csv_map_property_desc' => "La propriété (par exemple le nom de la colonne) de l'ensemble de données qui sera affiché Quand une visualisation de la carte est applicable.", + 'definition_date' => 'Date', + 'definition_date_desc' => 'Un point ou une période de temps associée à un événement dans le cycle de vie de la ressource. La meilleure pratique consiste à utiliser le schéma de la norme ISO 8601.', + 'definition_language' => 'Langue', + 'definition_language_desc' => 'La langue de la ressource', + 'definition_rights' => 'Droits', + 'definition_rights_description' => 'Informations sur les droits détenus dans et sur la ressource.', + 'definition_theme' => 'Thème', + 'definition_theme_description' => "Le thème ou la catégorie que l'ensemble de données appartient.", + 'definition_cache_minutes' => 'Cache', + 'definition_cache_minutes_desc' => 'Combien de temps cette ressource devrait être mis en cache (en minutes).', + 'definition_draft' => 'Ebauche', + 'definition_draft_desc' => "Ebauche de définitions ne sont pas présentés au public lors de sa création, mais l'espace URI qu'ils prennent est réservé.", + 'definition_publisher_uri' => "URI de l'editeur", + 'definition_publisher_uri_desc' => "L'URI de l'entité responsable de la publication du jeu de données (par exemple http://gov.be).", + 'definition_publisher_name' => "Nom de l'editeur", + 'definition_publisher_name_desc' => "Le nom de l'entité responsable de la publication du jeu de données.", + 'definition_keywords' => 'Mots-clés', + 'definition_keywords_desc' => "Une virgule liste de mots clés concernant l'ensemble de données séparée.", + 'definition_contact_point' => 'Point de contact', + 'definition_contact_point_desc' => 'Un lien sur lequel les gens peuvent fournir des commentaires.', + 'definition_rights' => 'Licence', + 'definition_rights_desc' => 'La license associée avec les données.', + 'definition_theme' => 'Thème', + 'definition_theme_desc' => 'Le thème associée aved les données.', + 'json_uri' => 'URI', + 'json_uri_desc' => "L'emplacement du fichier JSON, une URL ou un emplacement de fichier local.", + 'json_title' => 'Titre', + 'json_title_desc' => 'Un nom donné à la ressource.', + 'json_description' => 'Description', + 'json_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'json_map_property' => 'Carte propriété', + 'json_jsontype' => 'Type JSON', + 'json_jsontype_desc' => 'Indique si le document JSON est plaine ou a une structure spécifique.', + 'mongo_description' => 'Description', + 'mongo_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'mongo_host' => 'Hôte', + 'mongo_host_desc' => "L'hôte de la base de données MongoDB.", + 'mongo_database' => 'Base de données', + 'mongo_database_desc' => 'Le nom de la base de données où la collecte, qui doit être publié, réside.', + 'mongo_mongo_collection' => 'Collection', + 'mongo_mongo_collection_desc' => 'Le nom de la collection MongoDB', + 'mongo_port' => 'Port', + 'mongo_port_desc' => 'Le port de la base de données MongoDB où une connexion peut être mis en place.', + 'mongo_username' => "Nom d'utilisateur", + 'mongo_username_desc' => "Un nom d'utilisateur qui a lu des autorisations sur la collection fournie. Sécurité d'abord, assurez-vous que l'utilisateur a lu des autorisations uniquement.", + 'mongo_password' => 'Mot de passe', + 'mongo_password_desc' => "Le mot de passe pour l'utilisateur qui a les autorisations de lecture.", + 'mysql_host' => 'Hôte', + 'mysql_host_desc' => "L'hôte de la base de données MySQL.", + 'mysql_port' => 'Port', + 'mysql_port_desc' => 'Le port de la base de données MySQL où une connexion peut être mis en place.', + 'mysql_database' => 'Base de données', + 'mysql_database_desc' => 'Le nom de la base de données où la datatable, qui doit être publié, réside.', + 'mysql_username' => "Nom d'utilisateur", + 'mysql_username_desc' => "Un nom d'utilisateur qui a lu des autorisations sur la collection fournie. Sécurité d'abord, assurez-vous que l'utilisateur a lu des autorisations uniquement.", + 'mysql_password' => 'Mot de passe', + 'mysql_password_desc' => "Le mot de passe pour l'utilisateur qui a les autorisations de lecture.", + 'mysql_collation' => 'Collation', + 'mysql_collation_desc' => 'La classement de la datatable', + 'mysql_pk' => 'Clé primaire', + 'mysql_pk_desc' => 'This is a shortcut to define a primary key of this dataset. + The value must be the index of the column you want each row to be mapped on. + The pk property will never explicitly appear in the definition, but will manifest itself as part of a column property.', + 'mysql_query' => 'Query', + 'mysql_query_desc' => 'The query of which the results will be published as open data.', + 'mysql_map_property' => 'Propriété geo', + 'mysql_map_property_desc' => 'The property (e.g. column name) of the dataset that will be shown when a map visualization is applicable. Non geo-graphical datasets are not affected by this property.', + 'mysql_description' => 'Description', + 'mysql_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'rdf_uri' => 'URI', + 'rdf_uri_desc' => "L'URI du fichier RDF.", + 'rdf_title' => 'Titre', + 'rdf_title_desc' => 'Un nom donné à la ressource.', + 'rdf_description' => 'Description', + 'rdf_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'rdf_format' => 'Format', + 'rdf_format_desc' => 'Le format de votre contenu RDF, Tortle, XML, ...', + 'shp_uri' => 'URI', + 'shp_uri_desc' => "L'emplacement du fichier SHP, une URL ou un emplacement de fichier local.", + 'shp_title' => 'Titre', + 'shp_title_desc' => 'Un nom donné à la ressource.', + 'shp_description' => 'Description', + 'shp_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'shp_epsg' => 'EPSG', + 'shp_epsg_desc' => 'Ce paramètre contient le code EPSG dans lequel les propriétés géométriques dans le fichier de forme sont codés.', + 'shp_map_property' => 'Propriété geo', + 'shp_map_property_desc' => 'Le nom de la propriété qui identifie un objet à partir des données.', + 'sparql_endpoint' => 'SPARQL endpoint', + 'sparql_endpoint_desc' => "L'URI du SPARQL endpoint (par exemple http://foobar:8890/sparql-auth).", + 'sparql_title' => 'Titre', + 'sparql_title_desc' => 'Un nom donné à la ressource.', + 'sparql_description' => 'Description', + 'sparql_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'sparql_query' => 'SPARQL requête', + 'sparql_query_desc' => 'La requête à être exécutée.', + 'sparql_endpoint_user' => "Nom d'utilisateur du SPARQL endpoint", + 'sparql_endpoint_user_desc' => "Un nom d'utilisateur qui a lu des autorisations sur la collection fournie. Sécurité d'abord, assurez-vous que l'utilisateur a lu des autorisations uniquement.", + 'sparql_endpoint_password' => "Mot de passe", + 'sparql_endpoint_password_desc' => "Le mot de passe pour l'utilisateur qui a les autorisations de lecture.", + 'xls_uri' => 'URI', + 'xls_uri_desc' => "L'emplacement du fichier XLS, une URL ou un emplacement de fichier local.", + 'xls_title' => 'Titre', + 'xls_title_desc' => 'Un nom donné à la ressource.', + 'xls_description' => 'Description', + 'xls_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'xls_sheet' => 'Feuille de XLS', + 'xls_sheet_desc' => 'Le nom de la feuille dans laquelle les données de tableau réside.', + 'xls_has_header_row' => 'Tête de rang', + 'xls_has_header_row_desc' => "Un paramètre booléen qui définit si le fichier XLS contient une ligne d'en-tête de cette colonne contient les noms.", + 'xls_start_row' => 'Ligne de départ', + 'xls_start_row_desc' => "Un paramètre booléen qui définit si le fichier CSV contient une ligne d'en-tête de cette colonne contient les noms.", + 'xls_pk' => 'Clé primaire', + 'xls_pk_desc' => 'This is a shortcut to define a primary key of this dataset. The value must be the index of the column you want each row to be mapped on. The pk property will never explicitly appear in the definition, but will manifest itself as part of a column property.', + 'xls_map_property' => 'Carte propriété', + 'xls_map_property_desc' => "Ceci est un raccourci pour définir une clé primaire de cet ensemble de données. +                                 La valeur doit être l'indice de la colonne que vous voulez chaque rangée pour être plaqué. +                                 La propriété sélectionnée sera utilisée comme identifiant unique sur les objets qui seront mises en correspondance avec le format de sortie", + 'xml_uri' => 'URI', + 'xml_uri_desc' => "L'emplacement du fichier XML, une URL ou un emplacement de fichier local.", + 'xml_title' => 'Titre', + 'xml_title_desc' => 'Un nom donné à la ressource.', + 'xml_description' => 'Description', + 'xml_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'xml_geo_formatted' => 'KML', + 'xml_geo_formatted_desc' => 'Est-ce que le format du fichier XML, KML?', + 'installed_class' => 'Classe', + 'installed_class_desc' => 'Le nom du classe qui vous voulez publicer.', + 'installed_path' => 'Chemin de classe', + 'installed_path_desc' => 'Le chemin due classe, relative du dossier "/installed".', + 'installed_title' => 'Titre', + 'installed_title_desc' => 'Un nom donné à la ressource.', + 'installed_description' => 'Description', + 'installed_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'elasticsearch_description' => "Description", + 'elasticsearch_description_desc' => "Le texte descriptif ou d'information qui fournit un certain contexte pour vous publié des ensembles de données.", + 'elasticsearch_host' => "Hôte", + 'elasticsearch_host_desc' => "L'hôte d'Elasticsearch.", + 'elasticsearch_es_type' => "Type", + 'elasticsearch_es_type_desc' => "Le type de données à l'intérieur de l'index.", + 'elasticsearch_es_index' => "Index", + 'elasticsearch_es_index_desc' => "Le nom de l'index Elasticsearch.", + 'elasticsearch_port' => "Port", + 'elasticsearch_port_desc' => "Le port de la Elasticsearch.", + 'elasticsearch_username' => "Nom d'utilisateur", + 'elasticsearch_username_desc' => "Un nom d'utilisateur qui a lu des autorisations sur la collection fournie. Sécurité d'abord, assurez-vous que l'utilisateur a lu des autorisations uniquement.", + + 'elasticsearch_password' => "Mot de passe", + 'elasticsearch_password_desc' => "Le mot de passe pour l'utilisateur qui a les autorisations de lecture.", +); diff --git a/app/lang/fr/settings.php b/app/lang/fr/settings.php new file mode 100644 index 00000000..1191355e --- /dev/null +++ b/app/lang/fr/settings.php @@ -0,0 +1,16 @@ + "Paramètres généraux", + "title" => "Titre", + "title_help" => "Le nom que vous donnez au catalogue", + "description" => "Description", + "description_help" => "Description de l'ensemble de données moyenne.", + "publisher" => "Editeur", + "publisher_help" => "Le nom de l'entité qui est responsable pour le catalogue de données.", + "publisher_uri_help" => "L'URI de l'entité responsable de la publication du catalogue de données.", + "language" => "Langue", + "language_help" => "La langue de la plupart des jeux de données.", + "dcat_link" => "DCAT-AP lien", + "save" => "Sauver", +); diff --git a/app/lang/nl/admin.php b/app/lang/nl/admin.php new file mode 100644 index 00000000..9f3acc5c --- /dev/null +++ b/app/lang/nl/admin.php @@ -0,0 +1,63 @@ + "Voeg een dataset toe", + "required_parameters" => "Verplichte parameters", + "collection" => "Verzameling", + "build_identifier" => "Stel een publishing URI samen", + "select_type" => "Selecteer een databron en vul de nodige meta-data in", + "collection_help" => "Een enkele of samengestelde verzamelnaam (via een / -teken) om datasets te identificeren, bv. bossen of bossen/2015", + "resource_name" => "Datasetnaam", + "submit_issue" => "Voeg een issue toe", + "visit_site" => "Bezoeken onze website", + "resource_name_help" => "De specifieke naam van de dataset die na de verzamelnaam wordt geplaatst en als laatste stuk wordt gebruikt van de publishing URI. bv. walnootbomen", + "identifier" => "Identifier", + "type" => "Type", + "optional_parameters" => "Optionele parameters", + "caching" => "Caching", + "cache_for" => "Cache voor", + "minute" => "minute(n)", + "cache_help" => "Hoe lang moet deze dataset gecached worden? Vul 0 of -1 in om geen caching toe te passen.", + "dcat_header" => "Beschrijf je dataset", + "edit_dataset" => "Bewerk een dataset", + "parameters" => "Parameters", + "source_type" => "Brontype", + "header_dataset_panel" => "Beheer je datasets", + "add_button" => "Voeg toe", + "view_data" => "Data", + "view_definition" => "Definitie", + "no_datasets_message" => "Deze datatank bevat nog geen datasets.", + "no_datasets_filter_message" => "Er werden geen datasets gevonden via de filter.", + "header_group_panel" => "Beheer je groepen en rechten", + "rename" => "Bewerk de naam", + "edit" => "Bewerk", + "view" => "Bekijk", + "permissions" => "Rechten", + "all" => "Alles", + "save_permissions" => "Bewaar rechten", + "add_group" => "Voeg een groep toe", + "name" => "Naam", + "cancel" => "Annuleer", + "rename_group" => "Geef de groep een andere naam", + "save" => "Bewaar", + "header_user_panel" => "Beheer je gebruikers", + "user_you" => "jezelf", + "add_user" => "Voeg een gebruiker toe", + "username" => "Gebruikersnaam", + "group" => "Groep", + "edit_user" => "Bewerk een gebruiker", + "password" => "Wachtwoord", + "password_help" => "Laat dit veld leeg om het huidige wachtwoord te behouden.", + "sign_out" => "Uitloggen", + "admin" => "Admin", + "sign_in_header" => "Gelieve in te loggen", + "sign_in" => "Log in", + "admin_header" => "Datasets", + "menu_settings" => "Algemeen", + "menu_datasets" => "Datasets", + "menu_users" => "Gebruikers", + "menu_groups" => "Groepen" +); diff --git a/app/lang/nl/datasets.php b/app/lang/nl/datasets.php new file mode 100644 index 00000000..bf7ed5f1 --- /dev/null +++ b/app/lang/nl/datasets.php @@ -0,0 +1,15 @@ + "Collecties & datasets", + "filter" => "Filter", + "nothing_found_filter" => "Er werden geen collecties noch datasets gevonden met de huidige filter.", + "view_json" => "Bekijk als JSON", + "collection" => "Collectie", + "collection_description" => "Deze URI is een collectie en kan andere collecties of datasets bevinden.", + "formats" => "Formaten", + "description" => "Beschrijving", + "source_type" => "Brontype", + "license" => "Licentie", + "search_datasets" => "Zoek datasets", +); diff --git a/app/lang/nl/errors.php b/app/lang/nl/errors.php new file mode 100644 index 00000000..5543c1f5 --- /dev/null +++ b/app/lang/nl/errors.php @@ -0,0 +1,11 @@ + "Oops, er ging iets mis.", + '403' => "Oops, je hebt onvoldoende rechten om deze actie te voltooien.", + '404' => 'Oops, er lijkt hier helemaal niets te zijn!', + '500' => 'Oops, er ging iets fout!', + 'contact_us' => 'Als deze fout zich nog voordoet, neem gerust contact met ons op!', + 'submit_issue' => 'Maak een nieuwe melding op onze github.', + 'visit_site' => 'Bezoek onze website.', +); diff --git a/app/lang/nl/htmlview.php b/app/lang/nl/htmlview.php new file mode 100644 index 00000000..7eebf007 --- /dev/null +++ b/app/lang/nl/htmlview.php @@ -0,0 +1,11 @@ + "Formaten", + "description" => "Beschrijving", + "source_type" => "Bronbestand", + "license" => "Licentie", + "contact" => "Contact", + "publisher" => "Uitgever", + "keywords" => "Trefwoorden", +]; diff --git a/app/lang/nl/parameters.php b/app/lang/nl/parameters.php new file mode 100644 index 00000000..c3b4c76a --- /dev/null +++ b/app/lang/nl/parameters.php @@ -0,0 +1,163 @@ + 'URI', + 'csv_uri_desc' => 'De locatie van het CSV bestand, dit kan een URL zijn of een lokaal pad.', + 'csv_title' => 'Titel', + 'csv_title_desc' => 'Een titel voor de dataset.', + 'csv_description' => 'Beschrijving', + 'csv_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'csv_delimiter' => 'Scheidingsteken', + 'csv_delimiter_desc' => 'Het scheidingsteken van het CSV bestand.', + 'csv_has_header_row' => 'Hoofdrij', + 'csv_has_header_row_desc' => 'Een parameter die aangeeft of er een hoofdrij aanwezig is in de CSV die de kolomnamen bevat.', + 'csv_start_row' => 'Startrij', + 'csv_start_row_desc' => 'Definieer op welke rij de data (inclusief de hoofdrij indien aanwezig) begint in het CSV bestand.', + 'csv_pk' => 'Unieke ID', + 'csv_pk_desc' => 'Indien dit ingevuld wordt met de index van een kolom dan wordt de CSV data gemapped als een object, met als key de waarde van de ingevulde kolom.', + 'csv_map_property' => 'Geo-eigenschap', + 'csv_map_property_desc' => 'De naam van de kolom die wordt getoond op een map visualisatie, indien de CSV geografische data bevat.', + 'definition_date' => 'Datum', + 'definition_date_desc' => 'Een datum die gerelateerd is met de dataset, deze datum wordt best in een ISO8601 schema meegegeven.', + 'definition_language' => 'Taal', + 'definition_language_desc' => 'De taal van de databron.', + 'definition_rights' => 'Licentie', + 'definition_rights_description' => 'Informatie over de licentie die op deze dataset rust.', + 'definition_theme' => 'Thema', + 'definition_theme_description' => 'Het thema of category van deze dataset.', + 'definition_cache_minutes' => 'Cache', + 'definition_cache_minutes_desc' => 'Het aantal minuten dat deze dataset in cache mag blijven. Vul 0 of -1 in indien er geen cache toegepast mag worden.', + 'definition_draft' => 'Draft', + 'definition_draft_desc' => 'Draft datasets zijn niet zichtbaar voor het publiek, de URI die ze innemen is wel gereserveerd.', + 'definition_publisher_uri' => 'Uitgever', + 'definition_publisher_uri_desc' => 'De URI van de entiteit die verantwoordelijk is om deze dataset te publiceren.', + 'definition_publisher_name' => 'Uitgever naam', + 'definition_publisher_name_desc' => 'De naam van de entiteit die verantwoordelijk is om deze dataset te publiceren.', + 'definition_keywords' => 'Trefwoorden', + 'definition_keywords_desc' => 'Een lijst van trefwoorden gescheiden met een komma die deze dataset aangaan.', + 'definition_contact_point' => 'Contactpunt', + 'definition_contact_point_desc' => 'Een link waar mensen terecht kunnen met feedback of fouten.', + 'definition_rights' => 'Licentie', + 'definition_rights_desc' => 'De licentie van de data.', + 'definition_theme' => 'Thema', + 'definition_theme_desc' => 'Het thema geassocieerd met de data.', + 'json_uri' => 'URI', + 'json_uri_desc' => 'De locatie van het JSON bestand, dit kan een URL zijn of een lokaal pad.', + 'json_title' => 'Titel', + 'json_title_desc' => 'Een titel voor de dataset.', + 'json_description' => 'Beschrijving', + 'json_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'json_jsontype' => 'JSON type', + 'json_jsontype_desc' => 'Geef aan welke soort JSON het document bevat.', + 'json_map_property' => 'Map eigenschap', + 'mongo_description' => 'Beschrijving', + 'mongo_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'mongo_host' => 'Host', + 'mongo_host_desc' => 'De host van de MongoDB database.', + 'mongo_database' => 'Database', + 'mongo_database_desc' => 'De naam van de database waar de collectie van data in zit.', + 'mongo_mongo_collection' => 'Collectie', + 'mongo_mongo_collection_desc' => 'De naam van de collectie van waaruit de data moet gepubliceerd worden.', + 'mongo_port' => 'Poort', + 'mongo_port_desc' => 'De poort van de MongoDB database waarmee kan verbonden worden.', + 'mongo_username' => 'Gebruikersnaam', + 'mongo_username_desc' => 'Een gebruikersnaam die leesrechten heeft op de collectie.', + 'mongo_password' => 'Wachtwoord', + 'mongo_password_desc' => 'Het wachtwoord van de gebruiker.', + 'mysql_host' => 'Host', + 'mysql_host_desc' => 'De host van de MySQL database.', + 'mysql_port' => 'Poort', + 'mysql_port_desc' => 'De poort van de MySQL database waar een verbinding mee kan gemaakt worden.', + 'mysql_database' => 'Database', + 'mysql_database_desc' => 'De naam van de database waar de tabel die gepubliceerd moet worden, in zit.', + 'mysql_username' => 'Gebruikersnaam', + 'mysql_username_desc' => 'Een gebruikersnaam die leesrechten heeft op de collectie.', + 'mysql_password' => 'Wachtwoord', + 'mysql_password_desc' => 'Het wachtwoord van de gebruiker.', + 'mysql_collation' => 'Collatie', + 'mysql_collation_desc' => 'De collatie van de datatabel.', + 'mysql_pk' => 'Unieke ID', + 'mysql_pk_desc' => 'Indien dit ingevuld wordt met de index van een kolom dan wordt de MySQL data gemapped als een object, met als key de waarde van de ingevulde kolom.', + 'mysql_query' => 'Query', + 'mysql_query_desc' => 'De query waarvan de resultaten als open data worden gepubliceerd.', + 'mysql_description' => 'Beschrijving', + 'mysql_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'mysql_map_property' => 'Geo-eigenschap', + 'mysql_map_property_desc' => 'De naam van de kolom die wordt getoond op een map visualisatie, indien de CSV geografische data bevat.', + 'rdf_uri' => 'URI', + 'rdf_uri_desc' => 'De URI van het RDF bestand.', + 'rdf_title' => 'Titel', + 'rdf_title_desc' => 'Een titel voor de dataset.', + 'rdf_description' => 'Beschrijving', + 'rdf_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'rdf_format' => 'Formaat', + 'rdf_format_desc' => 'Het formaat waarin de RDF gestructureerd is (e.g. XML, Turtle).', + 'shp_uri' => 'URI', + 'shp_uri_desc' => 'De locatie van het SHP bestand, dit kan een lokaal pad zijn of een URI. Zorg ervoor dat op diezelfde locatie ook de bijkomstige bestanden voor het SHP bestand te vinden zijn.', + 'shp_title' => 'Titel', + 'shp_title_desc' => 'Een titel voor de dataset.', + 'shp_description' => 'Beschrijving', + 'shp_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'shp_epsg' => 'EPSG', + 'shp_epsg_desc' => 'De EPSG code van het SHP bestand.', + 'shp_map_property' => 'Geo-eigenschap', + 'shp_map_property_desc' => 'De naam van het veld die een object van de data identificeert.', + 'sparql_endpoint' => 'SPARQL endpoint', + 'sparql_endpoint_desc' => 'De URI van het SPARQL end-point (e.g. http://foobar:8890/sparql-auth).', + 'sparql_title' => 'Titel', + 'sparql_title_desc' => 'Een titel voor de dataset.', + 'sparql_description' => 'Beschrijving', + 'sparql_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'sparql_query' => 'SPARQL query', + 'sparql_query_desc' => 'De query waarvan de resultaten als open data worden gepubliceerd.', + 'sparql_endpoint_user' => 'Gebruikersnaam', + 'sparql_endpoint_user_desc' => 'De gebruiker die voldoende rechten heeft om het SPARQL endpoint te bevragen.', + 'sparql_endpoint_password' => "Wachtwoord", + 'sparql_endpoint_password_desc' => 'Wachtwoord van de gebruiker.', + 'xls_uri' => 'URI', + 'xls_uri_desc' => 'De locatie van het XLS file, dit kan een URI zijn of een lokaal pad.', + 'xls_title' => 'Titel', + 'xls_title_desc' => 'Een titel voor de dataset.', + 'xls_description' => 'Beschrijving', + 'xls_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'xls_sheet' => 'XLS werkblad', + 'xls_sheet_desc' => 'De naam van het werkblad waar de data die gepubliceerd moet worden in zit.', + 'xls_has_header_row' => 'Hoofdrij', + 'xls_has_header_row_desc' => 'Een parameter die aangeeft of er een hoofdrij aanwezig is in de CSV die de kolomnamen bevat.', + 'xls_start_row' => 'Startrij', + 'xls_start_row_desc' => 'Definieer op welke rij de data (inclusief de hoofdrij indien aanwezig) begint in het CSV bestand.', + 'xls_pk' => 'Unieke ID', + 'xls_pk_desc' => 'Indien dit ingevuld wordt met de index van een kolom dan wordt de CSV data gemapped als een object, met als key de waarde van de ingevulde kolom.', + 'xls_map_property' => 'Geo-eigenschap', + 'xls_map_property_desc' => 'De naam van de kolom die wordt getoond op een map visualisatie, indien de CSV geografische data bevat.', + 'xml_uri' => 'URI', + 'xml_uri_desc' => 'De locatie van het XML bestand, dit kan een URL zijn of een lokaal pad.', + 'xml_title' => 'Titel', + 'xml_title_desc' => 'Een titel voor de dataset.', + 'xml_description' => 'Beschrijving', + 'xml_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'xml_description' => 'KML', + 'xml_description_desc' => 'Is het XML document een KML?', + 'installed_class' => 'Klasse', + 'installed_class_desc' => 'De naam van de installed resource klasse.', + 'installed_path' => 'Pad', + 'installed_path_desc' => 'Het pad van de klasse, relatief van de /installed map.', + 'installed_uri' => 'URI', + 'installed_uri_desc' => 'De locatie van het CSV bestand, dit kan een URL zijn of een lokaal pad.', + 'installed_title' => 'Titel', + 'installed_title_desc' => 'Een titel voor de dataset.', + 'elasticsearch_description' => 'Beschrijving', + 'elasticsearch_description_desc' => 'Een korte tekst die context en extra informatie geeft bij de dataset.', + 'elasticsearch_host' => 'Host', + 'elasticsearch_host_desc' => 'De host van de Elasticsearch.', + 'elasticsearch_es_type' => 'Type', + 'elasticsearch_es_type_desc' => 'Het datatype dat uit de index van de Elasticsearch moet gepubliceerd worden.', + 'elasticsearch_es_index' => 'Index', + 'elasticsearch_es_index_desc' => 'De naam van de Elastichsearch index.', + 'elasticsearch_port' => 'Poort', + 'elasticsearch_port_desc' => 'De poort waarop de Elasticsearch bereikbaar is.', + 'elasticsearch_username' => 'Gebruikersnaam', + 'elasticsearch_username_desc' => 'De gebruiker die voldoende rechten heeft om het SPARQL endpoint te bevragen.', + 'elasticsearch_password' => 'Wachtwoord', + 'elasticsearch_password_desc' => 'Wachtwoord van de gebruiker.', +); diff --git a/app/lang/nl/settings.php b/app/lang/nl/settings.php new file mode 100644 index 00000000..522d1164 --- /dev/null +++ b/app/lang/nl/settings.php @@ -0,0 +1,16 @@ + "Algemene instellingen", + "title" => "Titel", + "title_help" => "De naam die je geeft aan de cataloog", + "description" => "Beschrijving", + "description_help" => "Beschrijving van de gemiddelde dataset.", + "publisher" => "Uitvoerder", + "publisher_help" => "De naam van de entiteit die verantwoordelijk is voor de datacataloog.", + "publisher_uri_help" => "De URI van de entiteit die verantwoordelijk is om de datacataloog te publiceren.", + "language" => "Taal", + "language_help" => "De taal van de meerderheid van de datasets.", + "dcat_link" => "DCAT-AP link", + "save" => "Bewaar", +); diff --git a/app/models/Definition.php b/app/models/Definition.php index c9ead71b..4e3ea1b3 100644 --- a/app/models/Definition.php +++ b/app/models/Definition.php @@ -16,13 +16,12 @@ class Definition extends Eloquent 'language', 'rights', 'cache_minutes', - 'draft', - 'map_property', 'keywords', 'publisher_uri', 'publisher_name', 'theme', - 'date' + 'date', + 'contact_point', ); /** @@ -44,13 +43,4 @@ public function delete() parent::delete(); } - - /** - * Draft is a tinyint, cast type true/false to - * the corrersponding integers in the back-end - */ - public function setDraftAttribute($value) - { - $this->attributes['draft'] = (int) $value; - } } diff --git a/app/models/dcat/License.php b/app/models/dcat/License.php index e26831f4..f51505eb 100644 --- a/app/models/dcat/License.php +++ b/app/models/dcat/License.php @@ -8,20 +8,10 @@ */ class License extends Eloquent { - - protected $boolean_values = array('domain_software','domain_content', 'domain_data', 'is_generic', 'is_okd_compliant', 'is_osi_compliant'); + protected $boolean_values = array(); protected $fillable = array( - 'domain_content', - 'domain_data', - 'domain_software', - 'family', 'license_id', - 'is_generic', - 'is_okd_compliant', - 'is_osi_compliant', - 'maintainer', - 'status', 'title', 'url' ); diff --git a/app/models/metadata/Geoprojection.php b/app/models/metadata/Geoprojection.php new file mode 100644 index 00000000..c9d7e3be --- /dev/null +++ b/app/models/metadata/Geoprojection.php @@ -0,0 +1,23 @@ + + */ +class Geoprojection extends Eloquent +{ + + protected $table = 'geoprojections'; + + protected $fillable = array('epsg', 'projection'); + + /** + * Return the polymorphic relation with a source type. + */ + public function source() + { + return $this->morphTo(); + } +} diff --git a/app/models/sourcetypes/CsvDefinition.php b/app/models/sourcetypes/CsvDefinition.php index e4e085c8..29940843 100644 --- a/app/models/sourcetypes/CsvDefinition.php +++ b/app/models/sourcetypes/CsvDefinition.php @@ -11,7 +11,7 @@ class CsvDefinition extends SourceType protected $table = 'csvdefinitions'; - protected $fillable = array('uri', 'delimiter', 'has_header_row', 'start_row', 'description', 'title'); + protected $fillable = array('uri', 'delimiter', 'has_header_row', 'start_row', 'description', 'title', 'map_property'); /** * Relationship with the TabularColumns model. diff --git a/app/models/sourcetypes/ElasticsearchDefinition.php b/app/models/sourcetypes/ElasticsearchDefinition.php new file mode 100644 index 00000000..421a2d4e --- /dev/null +++ b/app/models/sourcetypes/ElasticsearchDefinition.php @@ -0,0 +1,15 @@ + + */ +class ElasticsearchDefinition extends SourceType +{ + protected $table = 'elasticsearchdefinitions'; + + protected $fillable = array('host', 'es_type', 'es_index', 'port', 'username', 'password', 'description', 'title'); +} diff --git a/app/models/sourcetypes/JsonDefinition.php b/app/models/sourcetypes/JsonDefinition.php index 96f20046..f47856db 100644 --- a/app/models/sourcetypes/JsonDefinition.php +++ b/app/models/sourcetypes/JsonDefinition.php @@ -11,6 +11,6 @@ class JsonDefinition extends SourceType protected $table = 'jsondefinitions'; - protected $fillable = array('uri', 'description', 'title'); + protected $fillable = array('uri', 'description', 'title', 'jsontype'); } diff --git a/app/models/sourcetypes/JsonldDefinition.php b/app/models/sourcetypes/JsonldDefinition.php deleted file mode 100644 index e4940ec0..00000000 --- a/app/models/sourcetypes/JsonldDefinition.php +++ /dev/null @@ -1,16 +0,0 @@ - - */ -class JsonldDefinition extends SourceType -{ - - protected $table = 'jsonlddefinitions'; - - protected $fillable = array('uri', 'description', 'title'); - -} diff --git a/app/models/sourcetypes/MongoDefinition.php b/app/models/sourcetypes/MongoDefinition.php new file mode 100644 index 00000000..c82c2cbc --- /dev/null +++ b/app/models/sourcetypes/MongoDefinition.php @@ -0,0 +1,15 @@ + + */ +class MongoDefinition extends SourceType +{ + protected $table = 'mongodefinitions'; + + protected $fillable = array('host', 'mongo_collection', 'database', 'port', 'username', 'password', 'description', 'title'); +} diff --git a/app/models/sourcetypes/MysqlDefinition.php b/app/models/sourcetypes/MysqlDefinition.php index d8ca9ace..ee892c7c 100644 --- a/app/models/sourcetypes/MysqlDefinition.php +++ b/app/models/sourcetypes/MysqlDefinition.php @@ -12,7 +12,7 @@ class MysqlDefinition extends SourceType protected $table = 'mysqldefinitions'; - protected $fillable = array('host', 'port', 'database', 'username', 'password', 'collation', 'query'); + protected $fillable = array('host', 'port', 'database', 'username', 'password', 'collation', 'query', 'description'); /** * Relationship with the TabularColumns model. diff --git a/app/models/sourcetypes/ShpDefinition.php b/app/models/sourcetypes/ShpDefinition.php index 1a7c030b..2c0e3ced 100644 --- a/app/models/sourcetypes/ShpDefinition.php +++ b/app/models/sourcetypes/ShpDefinition.php @@ -12,7 +12,7 @@ class ShpDefinition extends SourceType protected $table = 'shpdefinitions'; - protected $fillable = array('uri', 'epsg', 'description', 'title'); + protected $fillable = array('uri', 'epsg', 'description', 'title', 'map_property'); /** * Relationship with the TabularColumns model. diff --git a/app/models/sourcetypes/XlsDefinition.php b/app/models/sourcetypes/XlsDefinition.php index 0d64cab2..5accf0fa 100644 --- a/app/models/sourcetypes/XlsDefinition.php +++ b/app/models/sourcetypes/XlsDefinition.php @@ -13,7 +13,7 @@ class XlsDefinition extends SourceType protected $table = 'xlsdefinitions'; - protected $fillable = array('uri', 'sheet', 'has_header_row', 'start_row', 'description', 'title'); + protected $fillable = array('uri', 'sheet', 'has_header_row', 'start_row', 'description', 'title', 'map_property'); /** * Relationship with the TabularColumns model. diff --git a/app/models/sourcetypes/XmlDefinition.php b/app/models/sourcetypes/XmlDefinition.php index e89983e3..e2470426 100644 --- a/app/models/sourcetypes/XmlDefinition.php +++ b/app/models/sourcetypes/XmlDefinition.php @@ -11,5 +11,5 @@ class XmlDefinition extends SourceType protected $table = 'xmldefinitions'; - protected $fillable = array('uri', 'description', 'title'); + protected $fillable = array('uri', 'description', 'title', 'geo_formatted'); } diff --git a/app/routes.php b/app/routes.php index 96734ade..f30f752b 100644 --- a/app/routes.php +++ b/app/routes.php @@ -25,6 +25,8 @@ Route::controller('users', 'Tdt\\Core\\Ui\\UserController'); Route::controller('groups', 'Tdt\\Core\\Ui\\GroupController'); + Route::get('language/{lang}', 'Tdt\\Core\\Ui\\LanguageController@setLanguage'); + Route::any('{all}', 'Tdt\\Core\\Ui\\UiController@handleRequest')->where('all', '.*'); }); @@ -56,10 +58,8 @@ $mimes = explode(',', $accept_header); if (in_array('text/html', $mimes) || in_array('application/xhtml+xml', $mimes)) { - // Create HTML response, seperate templates for status codes - switch ($code) - { + switch ($code) { case 403: return Response::view('errors.403', array('exception' => $exception), 403); break; @@ -74,7 +74,6 @@ return Response::view('errors.default', array('exception' => $exception), $code); } } else { - // Display a JSON error $error_json = new stdClass(); $error_json->error = new stdClass(); @@ -103,3 +102,12 @@ } }); + +App::finish(function ($request, $response) { + $tracker_id = \Config::get('tracker.id'); + + if (!empty($tracker_id)) { + $tracker = \App::make('Tdt\Core\Analytics\TrackerInterface'); + $tracker->track($request, $tracker_id); + } +}); diff --git a/app/start/artisan.php b/app/start/artisan.php index 8c1daf80..026b25ff 100644 --- a/app/start/artisan.php +++ b/app/start/artisan.php @@ -14,3 +14,5 @@ Artisan::add(new Tdt\Core\Commands\Export); Artisan::add(new Tdt\Core\Commands\Import); Artisan::add(new Tdt\Core\Commands\DcatThemes); +Artisan::add(new Tdt\Core\Commands\DcatLicenses); +Artisan::add(new Tdt\Core\Commands\GeoProjections); diff --git a/app/views/dataset/collection.blade.php b/app/views/dataset/collection.blade.php index 471ee3f4..73cd7ba3 100644 --- a/app/views/dataset/collection.blade.php +++ b/app/views/dataset/collection.blade.php @@ -3,11 +3,11 @@ @section('content')
-

Collections & datasets

+

{{ trans('datasets.list_header') }}

- +
@@ -27,7 +27,6 @@
@@ -66,7 +65,7 @@
   - No collection(s) or dataset(s) found with the filter '' + {{ trans('datasets.no_datasets_filter_message') }} ''
@@ -75,12 +74,12 @@
diff --git a/app/views/dataset/partials/details.blade.php b/app/views/dataset/partials/details.blade.php index 8375c560..5bcd5545 100644 --- a/app/views/dataset/partials/details.blade.php +++ b/app/views/dataset/partials/details.blade.php @@ -1,18 +1,22 @@
  • -
    Formats
    +
    {{ trans('htmlview.formats') }}
  • @if(!empty($source_definition['description']))
  • -
    Description
    +
    {{ trans('htmlview.description') }}

    {{ $source_definition['description'] }}

  • @endif
  • -
    Source Type
    +
    {{ trans('htmlview.source_type') }}

    {{ strtoupper($source_definition['type']) }}

  • @if(!empty($definition['rights']))
  • -
    License
    +
    {{ trans('htmlview.license') }}

    + @if (!empty($definition['rights_uri']) && filter_var($definition['rights_uri'], FILTER_VALIDATE_URL)) + {{ $definition['rights'] }} + @else {{ $definition['rights'] }} + @endif +

    +
  • + @endif + @if(!empty($definition['contact_point'])) +
  • +
    {{ trans('htmlview.contact') }}
    +

    + @if(filter_var($definition['contact_point'], FILTER_VALIDATE_URL)) + {{ $definition['contact_point'] }} + @else + {{ $definition['contact_point'] }} + @endif +

    +
  • + @endif + @if(!empty($definition['publisher_name'])) +
  • +
    {{ trans('htmlview.publisher') }}
    +

    + @if(!empty($definition['publisher_uri']) && filter_var($definition['publisher_uri'], FILTER_VALIDATE_URL)) + {{ $definition['publisher_name'] }} + @else + {{ $definition['publisher_name'] }} + @endif +

    +
  • + @endif + @if(!empty($definition['keywords'])) +
  • +
    {{ trans('htmlview.keywords') }}
    +

    + {{ $definition['keywords'] }}

  • @endif diff --git a/app/views/dataset/spectql.blade.php b/app/views/dataset/spectql.blade.php deleted file mode 100644 index 620f3864..00000000 --- a/app/views/dataset/spectql.blade.php +++ /dev/null @@ -1,25 +0,0 @@ -@extends('layouts.master') - -@section('content') - -
    -
    {{{ $body }}}
    -
    - -
    - -
    - -@stop \ No newline at end of file diff --git a/app/views/errors/403.blade.php b/app/views/errors/403.blade.php index 5cae6b4c..eef4b97d 100644 --- a/app/views/errors/403.blade.php +++ b/app/views/errors/403.blade.php @@ -18,7 +18,7 @@

403

-

Oops, it seems you don't have enough rights to access this!

+

{{ trans('errors.403') }}

{{ $exception->getMessage() }}

diff --git a/app/views/errors/404.blade.php b/app/views/errors/404.blade.php index fd5a4049..fc86f0a4 100644 --- a/app/views/errors/404.blade.php +++ b/app/views/errors/404.blade.php @@ -18,7 +18,7 @@

404

-

Oops, there is nothing here!

+

{{ trans('errors.404') }}

{{ $exception->getMessage() }}

diff --git a/app/views/errors/500.blade.php b/app/views/errors/500.blade.php index 3787edff..8d760629 100644 --- a/app/views/errors/500.blade.php +++ b/app/views/errors/500.blade.php @@ -18,7 +18,7 @@

500

-

Oops, we did something wrong!

+

{{ trans('errors.500') }}

@if(Config::get('app.debug'))
@@ -47,10 +47,10 @@
@else -

If this error persists, get in touch with us!

+

{{ trans('errors.contact_us') }}


-

Submit an issue to the repository

-

Visit our website

+

{{ trans('admin.submit_issue') }}

+

{{ trans('admin.visit_site') }}

@endif
diff --git a/app/views/errors/default.blade.php b/app/views/errors/default.blade.php index e8fa1727..4793398c 100644 --- a/app/views/errors/default.blade.php +++ b/app/views/errors/default.blade.php @@ -18,7 +18,7 @@

{{ $exception->getStatusCode() }}

-

Something went terribly wrong!

+

{{ trans('errors.400') }}

{{ $exception->getMessage() }}

diff --git a/app/views/home.blade.php b/app/views/home.blade.php index 0237b24a..c2790458 100644 --- a/app/views/home.blade.php +++ b/app/views/home.blade.php @@ -50,9 +50,9 @@
   @if(count($definitions) == 0) - This datatank is hungry for data, no datasets were added yet. + {{ trans('datasets.no_datasets_message') }} @else - No dataset(s) found with the filter '' + {{ trans('datasets.no_datasets_filter_message') }}'' @endif
@@ -63,8 +63,22 @@ @section('navigation') + + + @if(!empty($tracker_id)) + + @endif @stop \ No newline at end of file diff --git a/app/views/layouts/admin.blade.php b/app/views/layouts/admin.blade.php index 92543b63..3a0fca8c 100644 --- a/app/views/layouts/admin.blade.php +++ b/app/views/layouts/admin.blade.php @@ -15,7 +15,7 @@