From f3a151c2ab542e80be54705a91af69d7ecde561f Mon Sep 17 00:00:00 2001 From: Thomas Francart Date: Mon, 4 Jan 2021 17:05:35 +0100 Subject: [PATCH 1/3] merge skosmos master (#19) * PhpStorm: declare variable * PhpStorm: improve jquery efficiency, by avoiding locating elements multiple times * PhpStorm: remove duplicate keys in .jshintrc (same value too) * PhpStorm: typos * enhancement for passing plugin parameters from config.ttl * Initial implementation of shortening property value lists * Added a missing line * Fix shortening property value lists after ajax page load and other special cases * Translations for "show all # values" message + fix msgid for similar paths message * Added tests, simplified array handing in twig * updated translations * Increase property value cutoff limit from 10 to 15 * optimize jQuery expressions * Add Danish translation by Sebastian Esp Nielsen and A I * Updated translations * Avoid displaying empty type field in search result list. Fixes #942 * Add indexLetters REST method, with test. Part of #599 * Add Portuguese translation by Bruno Almeida and Laureano Macedo * Add indexConcepts REST method, with test. Part of #599 * Updated Portuguese translation after revision by @kinow * Implement limit and offset parameters for REST index method. Part of #599 * simplify limit determination (and don't default to 250) * avoid unnecessary repeated calls to getQueryParam * Add Brazilian Portuguese translation * Add Swagger documentation for index/ REST method (indexLetters) * Add Swagger documentation for index/ REST method (indexConcepts) * more specific definition of indexConcepts return type * Move modified date related methods to Controller * Move skosmos:useModifiedDate to global configuration, instead of per vocabulary * Simplify signature of GlobalConfiguration::getUseModifiedDate * Add helper method notModified in Controller class * Add 304 for global and vocabulary methods * Add 304 for global and concept methods * Update tests for the new code * Make Vocabulary and Concept Modifiables * Use vocabulary modified date * Move flag for enabling 304 back to VocabularyConfig, and make it available to Modifiables * Updating tests for latest changes * Fix scrutinizer errors * fix unit test that broke during merge conflict resolution * Use timestamp of default concept scheme as modified date for Vocabulary + tests * Fall back to Vocabulary->getModified if concept doesn't have a modified date * Remove unused method getConceptModifiedDate and corresponding tests (snif!) * attempt to fix some errors reported by Scrutinizer * Annotate the $modifiedResource as a possible DateTime literal, and check for its type using instanceof * Use Literal\Date (its getValue() returns a PHP DateTime too) and replace deprecated @expectedException annotation * Add swagger information for 304 response in REST methods * Add swagger information for the vocid/mappings REST endpoint (includes 304 not modified information) * Enhancement for listing altLabels and hiddenLabels for a REST API method * Added tests for GenericSparql * generate the label list with a single sparql query instead of two * Refactored code, no change in overall functionality * Simplified the way labels are passed by queryAllConceptLabels to RestController from GenericSparql * Differentiate between nonexistent concept and concept without prefLabel * Initial implementation of global REST label method. Fixes #952 * Add swagger spec for global labels method (and fix up some descriptions) * Proper HTTP date format (RFC 1123); read If-Modified-Since header using filter_input * initial draft for the REST API methods returning new and modified concepts for a vocabulary * Separated the functionality of WebController and RestController when forming the change list * Amended tests to reflect the change in functionality * Timestamps passed from vocabulary as native PHP dateTimes, then processed by each controller to the format they need * Added handling of malformed date strings and tests * Fixed a method argument * Fixed a method argument * using a PHP 7.1 compatible way for formating DateTime object * Numerous style tweaks. Added a limit parameter to parameterize the size of the list of changed concepts. * Additional documentation for mappings-method * fixed a parameter name * fix typo in test name * foreign language/explicit language detection improved;fixes #903 * initial draft for the REST API methods returning new and modified concepts for a vocabulary * Separated the functionality of WebController and RestController when forming the change list * Amended tests to reflect the change in functionality * Timestamps passed from vocabulary as native PHP dateTimes, then processed by each controller to the format they need * Added handling of malformed date strings and tests * Fixed a method argument * Fixed a method argument * using a PHP 7.1 compatible way for formating DateTime object * Numerous style tweaks. Added a limit parameter to parameterize the size of the list of changed concepts. * Refactored methods, added swagger documentation * implement language-aware sorting for altLabels; fixes #835 * add tests; fix mergeing arrays * initial test data for #554 configurable property order feature * initial support for ISO 25964 property order * initial support for defining a custom property order * Render concept groups and arrays using the same template used for other properties * fix sorting of concept properties in unknown URI namespaces * handle case when concept vocab is unknown; switch to class constants for order definitions * Fix and test for bad/unknown property order case * Ensure ISO 25964 order definition contains all common concept properties even though not all are mentioned in the ISO standard * Fix the font definitions for timestamps and linked vocabulary names, mentioned in #974 * update the testing assertions to address issues related to updating the test vocab * cleaning up the code * Show tooltips (rdfs:comment or skos:definition) for custom properties. Fixes #824 * Add missing variable declaration & change variable name to tooltip * Add unit test for custom property tooltip/description * Added tests. Fixed abiguity between the namespace prefixes dc, dct, dc11. * created & modified properties moved to the correct namespace * Add unit test for custom property missing a description * add missing phpdoc parameter declarations * simplify template a little bit by cutting an else expression * Handling and tests for malformed dates * Minor library dependency updates * fix accidental merge conflict resolve bug * fixes #990 via introducting new global js variable * Fixed PHPDoc comments * search result listing now correctly shows foreign labels (fix regression introduced by #993 * introduce a space between notation and prefLabel in mappings * Fix loading spinner that broke in refactoring commit 4fbfdce0053b7bb17f2209de1ded331f44e30c8e * Declare required PHP extensions using Composer * Fix double display of concept group on result page (caused by PR #992) * mappings: fix issue with explicitLanguageTags set to true and label is just shortened property; fix property text help * Upgrade bootstrap-multiselect and uri.js to versions that are actually available * rollback few libraries that require more testing * mark the start of 2.8 development * fix #1018 by explicitly declaring the UI locale in getDate() * Fixes #1027 by commenting out css file path * Fix error in swagger spec for search method return value The `results` field, which contains the search results, was incorrectly called `vocabularies` in the swagger spec - looks like a copy-paste error. * Add HTML classes for properties so they can be targeted in JS and CSS. Fixes #1034 * Focus should not be forced in the search field through js * Set the skip to main element link to cover both the page's main content and the side bar * Add property-specific classes also for mapping properties * remove dead code: the renderPropertyMappingValues function is never used * translations and tweaks * restored an id attribute * update twig; references #918 * Moved the main element deeper in the DOM tree * add screen reader class * changed concept and vocab info to flex boxes from the old table implementation * element closing order fixed * tweaks to the property divider on vocab info page * tweaked paddings for the dynamic layout of concept and vocabulary info * layout tweaks to concept page and vocabulary info page * Don't hide outlines of active links, which cause accessibility problems * Make it possible to use the Help link using keyboard only * reenable outlines to make it possible to do keyboard only tab navigation * Show the skip to content link when it receives keyboard focus * Add an outline offset to make the outlines look a bit nicer * Set an explicit outline, to ensure similar rendering across browsers * changed concept and vocab info to flex boxes from the old table implementation * tweaks to the property divider on vocab info page * tweaked paddings for the dynamic layout of concept and vocabulary info * layout tweaks to concept page and vocabulary info page * adjust position of skip to content link * replicating the vocab info spacer bar position of the old layout * Add an outline also to the content language selection when active * Add outline to multi-vocabulary selection on front page * Give the search button an outline when active; adjust background active color as well * Make outline visible on vocabulary headline (display: block prevented it) * Add tabindex=-1 to the main content element, to benefit eg screen readers * WCAG: fix front page heading structure * fix issue with focus (tested with Edge + Windows Narrator * fix focus outline issues on front page * fixes focus z-index; fixes topbar focus on ontology page * add screen reader only heading to search * incorporating headings into vocabulary info page; started implementing headings to sidebar * Changed a class name that caused conflicts between bootstrap and Skosmos css * Added a missing class attribute * main sidebar + alphabetical listing now support heading navigation; yet missing translations * fix color and border issues in sidebar buttons * changes subpage now support headings * add support for headings in groupings * add headings to vocab.twig * relocated .sidebar-grey heading so that jstree does not interfere with it * fix regressions encountered on vocabulary search page * fix css problem with '!*' in alphabetical listing spanning over two lines * add accessibility headings to search result page; addresses #1039 * fix regressions in vocabulary page; fix a bug introduced by using headings in alphabetical listing * concept info page to use headings; addresses #1038 * fix screen reader explanation for changes tab * minor adjustments to about page * remove unused code * adjust about page layout + css a bit * revert topbar #service-name height settings set by #1060 * somewhat working front page * intermediate testing phase for topbar layout * similar functionality in headerbar in both vocabulary and front page * fix responsivity issues with header-float * fix topbar margin/padding issue when under 1260px width; positional uiLanguageDropdown instead of fixed * New translation strings for screen reader helper texts in fi, en, sv * Assort replaced with list * Adjust focus CSS styles: dotted outline, which is not shown for main content block * CSS fix: Make sure concept info area extends to the full available width * Fix position of concept spinner, which was broken by a -moz-fit-width rule. * tweaked header font size * fixed translation template names * criteria -> criterion * Fixed event listener for alphabetical concept listing * fix focused pagination letter background color * Show short name of vocabulary for property values from another vocab * Fix typo in swagger.json offset description * Use GRAPH, not FROM in alphabetical letters query - much faster on Fuseki * use GRAPH, not FROM in single alphabetical letter query - much faster on Fuseki Co-authored-by: Bruno P. Kinoshita Co-authored-by: Osma Suominen Co-authored-by: Joeli Takala Co-authored-by: joelit Co-authored-by: Bruno Almeida Co-authored-by: kouralex <1723419+kouralex@users.noreply.github.com> Co-authored-by: Ahonen Mika J Co-authored-by: Vainonen Co-authored-by: Minttu Hurme --- .codeclimate.yml | 3 +- .gitignore | 10 +- .jshintrc | 6 +- .sonarcloud.properties | 15 + .travis.yml | 36 +- Dockerfile | 11 + README.md | 4 +- Vagrantfile | 27 + ansible.cfg | 3 + ansible/playbook.yml | 13 + ansible/roles/base/tasks/main.yml | 5 + ansible/roles/fuseki/files/fuseki | 5 + ansible/roles/fuseki/files/skosmos.ttl | 58 + ansible/roles/fuseki/tasks/main.yml | 145 + ansible/roles/openjdk/tasks/main.yml | 5 + ansible/roles/skosmos/files/000-default.conf | 16 + ansible/roles/skosmos/files/config.ttl | 157 + ansible/roles/skosmos/tasks/main.yml | 64 + composer.json | 64 +- config.inc.dist | 71 - config.ttl.dist | 130 + controller/Controller.php | 233 +- controller/EntityController.php | 22 +- controller/Honeypot.php | 9 +- controller/RestController.php | 382 +- controller/WebController.php | 172 +- docker-compose.yml | 30 + entity.php | 4 +- migrate-config.php | 153 + model/BaseConfig.php | 64 + model/Cache.php | 17 +- model/Concept.php | 547 ++- model/ConceptMappingPropertyValue.php | 173 +- model/ConceptProperty.php | 75 +- model/ConceptPropertyValue.php | 61 +- model/ConceptPropertyValueLiteral.php | 29 +- model/ConceptSearchParameters.php | 53 +- model/DataObject.php | 13 +- model/GlobalConfig.php | 319 +- model/LabelSkosXL.php | 41 + model/Model.php | 206 +- model/Modifiable.php | 18 + model/PluginRegister.php | 55 +- model/Request.php | 62 +- model/SkosmosTurtleParser.php | 2 +- model/Vocabulary.php | 96 +- model/VocabularyConfig.php | 283 +- model/resolver/LOCResource.php | 33 + model/resolver/LinkedDataResource.php | 30 + model/resolver/RemoteResource.php | 26 + model/resolver/Resolver.php | 35 + model/resolver/WDQSResource.php | 53 + model/sparql/GenericSparql.php | 371 +- model/sparql/JenaTextSparql.php | 45 +- phpunit.xml | 9 +- resource/css/styles.css | 663 +-- resource/fonts/eot/FiraMono-Bold.eot | Bin 123608 -> 82269 bytes resource/fonts/eot/FiraMono-Medium.eot | Bin 0 -> 75902 bytes resource/fonts/eot/FiraMono-Regular.eot | Bin 129028 -> 76236 bytes resource/fonts/eot/FiraSans-Bold.eot | Bin 104072 -> 170744 bytes resource/fonts/eot/FiraSans-BoldItalic.eot | Bin 107408 -> 180902 bytes resource/fonts/eot/FiraSans-Book.eot | Bin 0 -> 161110 bytes resource/fonts/eot/FiraSans-BookItalic.eot | Bin 0 -> 170237 bytes resource/fonts/eot/FiraSans-Eight.eot | Bin 0 -> 154266 bytes resource/fonts/eot/FiraSans-EightItalic.eot | Bin 0 -> 162332 bytes resource/fonts/eot/FiraSans-ExtraBold.eot | Bin 0 -> 171194 bytes .../fonts/eot/FiraSans-ExtraBoldItalic.eot | Bin 0 -> 183203 bytes resource/fonts/eot/FiraSans-ExtraLight.eot | Bin 0 -> 157210 bytes .../fonts/eot/FiraSans-ExtraLightItalic.eot | Bin 0 -> 165368 bytes resource/fonts/eot/FiraSans-Four.eot | Bin 0 -> 150700 bytes resource/fonts/eot/FiraSans-FourItalic.eot | Bin 0 -> 161348 bytes resource/fonts/eot/FiraSans-Hair.eot | Bin 0 -> 157172 bytes resource/fonts/eot/FiraSans-HairItalic.eot | Bin 0 -> 166100 bytes resource/fonts/eot/FiraSans-Heavy.eot | Bin 0 -> 169722 bytes resource/fonts/eot/FiraSans-HeavyItalic.eot | Bin 0 -> 180786 bytes resource/fonts/eot/FiraSans-Italic.eot | Bin 0 -> 166494 bytes resource/fonts/eot/FiraSans-Light.eot | Bin 120388 -> 157971 bytes resource/fonts/eot/FiraSans-LightItalic.eot | Bin 125120 -> 165107 bytes resource/fonts/eot/FiraSans-Medium.eot | Bin 105816 -> 162425 bytes resource/fonts/eot/FiraSans-MediumItalic.eot | Bin 109360 -> 171092 bytes resource/fonts/eot/FiraSans-Regular.eot | Bin 110636 -> 158105 bytes resource/fonts/eot/FiraSans-SemiBold.eot | Bin 0 -> 170580 bytes .../fonts/eot/FiraSans-SemiBoldItalic.eot | Bin 0 -> 180331 bytes resource/fonts/eot/FiraSans-Thin.eot | Bin 0 -> 156702 bytes resource/fonts/eot/FiraSans-ThinItalic.eot | Bin 0 -> 164191 bytes resource/fonts/eot/FiraSans-Two.eot | Bin 0 -> 146691 bytes resource/fonts/eot/FiraSans-TwoItalic.eot | Bin 0 -> 154139 bytes resource/fonts/eot/FiraSans-Ultra.eot | Bin 0 -> 179372 bytes resource/fonts/eot/FiraSans-UltraItalic.eot | Bin 0 -> 191793 bytes resource/fonts/eot/FiraSans-UltraLight.eot | Bin 0 -> 157218 bytes .../fonts/eot/FiraSans-UltraLightItalic.eot | Bin 0 -> 164160 bytes resource/fonts/ttf/FiraMono-Bold.ttf | Bin 134512 -> 206548 bytes resource/fonts/ttf/FiraMono-Medium.ttf | Bin 0 -> 173516 bytes resource/fonts/ttf/FiraMono-Regular.ttf | Bin 140212 -> 174632 bytes resource/fonts/ttf/FiraSans-Bold.ttf | Bin 190072 -> 438028 bytes resource/fonts/ttf/FiraSans-BoldItalic.ttf | Bin 193724 -> 447536 bytes resource/fonts/ttf/FiraSans-Book.ttf | Bin 0 -> 404400 bytes resource/fonts/ttf/FiraSans-BookItalic.ttf | Bin 0 -> 412324 bytes resource/fonts/ttf/FiraSans-Eight.ttf | Bin 0 -> 389804 bytes resource/fonts/ttf/FiraSans-EightItalic.ttf | Bin 0 -> 398736 bytes resource/fonts/ttf/FiraSans-ExtraBold.ttf | Bin 0 -> 446680 bytes .../fonts/ttf/FiraSans-ExtraBoldItalic.ttf | Bin 0 -> 456844 bytes resource/fonts/ttf/FiraSans-ExtraLight.ttf | Bin 0 -> 394544 bytes .../fonts/ttf/FiraSans-ExtraLightItalic.ttf | Bin 0 -> 402596 bytes resource/fonts/ttf/FiraSans-Four.ttf | Bin 0 -> 384504 bytes resource/fonts/ttf/FiraSans-FourItalic.ttf | Bin 0 -> 399104 bytes resource/fonts/ttf/FiraSans-Hair.ttf | Bin 0 -> 400196 bytes resource/fonts/ttf/FiraSans-HairItalic.ttf | Bin 0 -> 410704 bytes resource/fonts/ttf/FiraSans-Heavy.ttf | Bin 0 -> 458684 bytes resource/fonts/ttf/FiraSans-HeavyItalic.ttf | Bin 0 -> 467704 bytes resource/fonts/ttf/FiraSans-Italic.ttf | Bin 0 -> 411640 bytes resource/fonts/ttf/FiraSans-Light.ttf | Bin 218880 -> 397116 bytes resource/fonts/ttf/FiraSans-LightItalic.ttf | Bin 223928 -> 404244 bytes resource/fonts/ttf/FiraSans-Medium.ttf | Bin 192856 -> 404728 bytes resource/fonts/ttf/FiraSans-MediumItalic.ttf | Bin 196728 -> 413096 bytes resource/fonts/ttf/FiraSans-Regular.ttf | Bin 200120 -> 403924 bytes resource/fonts/ttf/FiraSans-SemiBold.ttf | Bin 0 -> 437824 bytes .../fonts/ttf/FiraSans-SemiBoldItalic.ttf | Bin 0 -> 446524 bytes resource/fonts/ttf/FiraSans-Thin.ttf | Bin 0 -> 395964 bytes resource/fonts/ttf/FiraSans-ThinItalic.ttf | Bin 0 -> 402844 bytes resource/fonts/ttf/FiraSans-Two.ttf | Bin 0 -> 382148 bytes resource/fonts/ttf/FiraSans-TwoItalic.ttf | Bin 0 -> 392156 bytes resource/fonts/ttf/FiraSans-Ultra.ttf | Bin 0 -> 485356 bytes resource/fonts/ttf/FiraSans-UltraItalic.ttf | Bin 0 -> 497216 bytes resource/fonts/ttf/FiraSans-UltraLight.ttf | Bin 0 -> 393952 bytes .../fonts/ttf/FiraSans-UltraLightItalic.ttf | Bin 0 -> 402308 bytes resource/fonts/woff/FiraMono-Bold.woff | Bin 63630 -> 94732 bytes resource/fonts/woff/FiraMono-Medium.woff | Bin 0 -> 86160 bytes resource/fonts/woff/FiraMono-Regular.woff | Bin 64994 -> 86572 bytes resource/fonts/woff/FiraSans-Bold.woff | Bin 89534 -> 198080 bytes resource/fonts/woff/FiraSans-BoldItalic.woff | Bin 92217 -> 209004 bytes resource/fonts/woff/FiraSans-Book.woff | Bin 0 -> 185904 bytes resource/fonts/woff/FiraSans-BookItalic.woff | Bin 0 -> 195408 bytes resource/fonts/woff/FiraSans-Eight.woff | Bin 0 -> 179116 bytes resource/fonts/woff/FiraSans-EightItalic.woff | Bin 0 -> 188976 bytes resource/fonts/woff/FiraSans-ExtraBold.woff | Bin 0 -> 200908 bytes .../fonts/woff/FiraSans-ExtraBoldItalic.woff | Bin 0 -> 212852 bytes resource/fonts/woff/FiraSans-ExtraLight.woff | Bin 0 -> 182012 bytes .../fonts/woff/FiraSans-ExtraLightItalic.woff | Bin 0 -> 191176 bytes resource/fonts/woff/FiraSans-Four.woff | Bin 0 -> 174800 bytes resource/fonts/woff/FiraSans-FourItalic.woff | Bin 0 -> 188024 bytes resource/fonts/woff/FiraSans-Hair.woff | Bin 0 -> 182312 bytes resource/fonts/woff/FiraSans-HairItalic.woff | Bin 0 -> 192788 bytes resource/fonts/woff/FiraSans-Heavy.woff | Bin 0 -> 200676 bytes resource/fonts/woff/FiraSans-HeavyItalic.woff | Bin 0 -> 212700 bytes resource/fonts/woff/FiraSans-Italic.woff | Bin 0 -> 192184 bytes resource/fonts/woff/FiraSans-Light.woff | Bin 95406 -> 182984 bytes resource/fonts/woff/FiraSans-LightItalic.woff | Bin 98125 -> 191400 bytes resource/fonts/woff/FiraSans-Medium.woff | Bin 89883 -> 186824 bytes .../fonts/woff/FiraSans-MediumItalic.woff | Bin 92565 -> 197376 bytes resource/fonts/woff/FiraSans-Regular.woff | Bin 91946 -> 183268 bytes resource/fonts/woff/FiraSans-SemiBold.woff | Bin 0 -> 198128 bytes .../fonts/woff/FiraSans-SemiBoldItalic.woff | Bin 0 -> 208040 bytes resource/fonts/woff/FiraSans-Thin.woff | Bin 0 -> 181896 bytes resource/fonts/woff/FiraSans-ThinItalic.woff | Bin 0 -> 190040 bytes resource/fonts/woff/FiraSans-Two.woff | Bin 0 -> 171160 bytes resource/fonts/woff/FiraSans-TwoItalic.woff | Bin 0 -> 180328 bytes resource/fonts/woff/FiraSans-Ultra.woff | Bin 0 -> 212040 bytes resource/fonts/woff/FiraSans-UltraItalic.woff | Bin 0 -> 225024 bytes resource/fonts/woff/FiraSans-UltraLight.woff | Bin 0 -> 181508 bytes .../fonts/woff/FiraSans-UltraLightItalic.woff | Bin 0 -> 189656 bytes resource/js/docready.js | 228 +- resource/js/groups.js | 4 +- resource/js/hierarchy.js | 55 +- resource/js/jquery.mCustomScrollbar.min.js | 2 - resource/js/jquery.mousewheel.min.js | 12 - resource/js/jquery.qtip.min.js | 4 - resource/js/lscache.min.js | 1 - resource/js/scripts.js | 199 +- resource/js/waypoints.min.js | 8 - resource/pics/type.gif | Bin 0 -> 1036 bytes .../translations/ar/LC_MESSAGES/skosmos.mo | Bin 0 -> 13501 bytes .../translations/da/LC_MESSAGES/skosmos.mo | Bin 0 -> 10965 bytes .../translations/de/LC_MESSAGES/skosmos.mo | Bin 11458 -> 11718 bytes .../translations/en/LC_MESSAGES/skosmos.mo | Bin 10783 -> 12830 bytes .../translations/es/LC_MESSAGES/skosmos.mo | Bin 9174 -> 9124 bytes .../translations/fa/LC_MESSAGES/skosmos.mo | Bin 0 -> 13490 bytes .../translations/fi/LC_MESSAGES/skosmos.mo | Bin 11098 -> 13104 bytes .../translations/fr/LC_MESSAGES/skosmos.mo | Bin 11433 -> 11373 bytes .../translations/it/LC_MESSAGES/skosmos.mo | Bin 11292 -> 11242 bytes .../translations/nb/LC_MESSAGES/skosmos.mo | Bin 10931 -> 11300 bytes .../translations/nl/LC_MESSAGES/skosmos.mo | Bin 0 -> 11199 bytes .../translations/nn/LC_MESSAGES/skosmos.mo | Bin 10764 -> 11088 bytes .../translations/pl/LC_MESSAGES/skosmos.mo | Bin 11348 -> 11305 bytes .../translations/pt/LC_MESSAGES/skosmos.mo | Bin 0 -> 11890 bytes .../translations/pt_BR/LC_MESSAGES/skosmos.mo | Bin 0 -> 11837 bytes .../translations/ru/LC_MESSAGES/skosmos.mo | Bin 0 -> 15095 bytes resource/translations/skosmos_ar.po | 770 +++ resource/translations/skosmos_da.po | 771 ++++ resource/translations/skosmos_de.po | 188 +- resource/translations/skosmos_en.mo | Bin 10783 -> 11126 bytes resource/translations/skosmos_en.po | 86 +- resource/translations/skosmos_es.po | 65 +- resource/translations/skosmos_fa.po | 771 ++++ resource/translations/skosmos_fi.mo | Bin 11098 -> 11454 bytes resource/translations/skosmos_fi.po | 229 +- resource/translations/skosmos_fr.po | 77 +- resource/translations/skosmos_it.po | 65 +- resource/translations/skosmos_nb.po | 75 +- resource/translations/skosmos_nl.po | 773 ++++ resource/translations/skosmos_nn.po | 69 +- resource/translations/skosmos_pl.po | 82 +- resource/translations/skosmos_pt.po | 770 +++ resource/translations/skosmos_pt_BR.po | 770 +++ resource/translations/skosmos_ru.po | 770 +++ resource/translations/skosmos_sv.mo | Bin 11065 -> 11391 bytes resource/translations/skosmos_sv.po | 222 +- resource/translations/skosmos_zh.po | 65 +- .../translations/sv/LC_MESSAGES/skosmos.mo | Bin 11065 -> 13000 bytes .../translations/zh/LC_MESSAGES/skosmos.mo | Bin 8501 -> 8451 bytes rest.php | 20 + swagger.json | 4110 ++++++++++------- tests/.gitignore | 2 +- tests/BreadcrumbTest.php | 6 +- tests/ConceptMappingPropertyValueTest.php | 91 +- tests/ConceptPropertyTest.php | 83 +- tests/ConceptPropertyValueLiteralTest.php | 32 +- tests/ConceptPropertyValueTest.php | 50 +- tests/ConceptSearchParametersTest.php | 95 +- tests/ConceptTest.php | 238 +- tests/DataObjectTest.php | 7 +- tests/FeedbackTest.php | 16 +- tests/GenericSparqlTest.php | 417 +- tests/GlobalConfigTest.php | 341 +- tests/Http304Test.php | 238 + tests/JenaTextSparqlTest.php | 199 +- tests/ModelTest.php | 92 +- tests/PluginRegisterTest.php | 22 +- tests/RequestTest.php | 41 +- tests/ResolverTest.php | 51 + tests/RestControllerTest.php | 423 ++ tests/VocabularyCategoryTest.php | 22 +- tests/VocabularyConfigTest.php | 260 +- tests/VocabularyDataObjectTest.php | 6 +- tests/VocabularyTest.php | 228 +- tests/WebControllerTest.php | 229 + tests/bootstrap.php | 4 +- tests/fuseki-assembler.ttl | 111 +- tests/init_fuseki.sh | 38 +- tests/jenatestconfig.inc | 5 - ...estvocabularies.ttl => jenatestconfig.ttl} | 146 +- tests/test-vocab-data/cbd.ttl | 54 + tests/test-vocab-data/changes.ttl | 2 +- tests/test-vocab-data/date.ttl | 3 +- tests/test-vocab-data/dup.ttl | 24 +- tests/test-vocab-data/dupgroup.ttl | 21 + tests/test-vocab-data/http304.ttl | 52 + tests/test-vocab-data/marc-fi.mrcx | 198 + tests/test-vocab-data/marc-sv.mrcx | 262 ++ tests/test-vocab-data/marc-undefined.mrcx | 198 + tests/test-vocab-data/myns-ontology.ttl | 21 + tests/test-vocab-data/sub.ttl | 2 +- .../test-vocab-data/test-concept-schemes.ttl | 56 + tests/test-vocab-data/test-marc.ttl | 41 + tests/test-vocab-data/test-notation-sort.ttl | 146 + .../test-qualified-broader.ttl | 24 + .../test-qualified-notation.ttl | 32 + tests/test-vocab-data/test.ttl | 20 +- tests/test-vocab-data/xl.ttl | 28 + .../testconfig-fordefaults.ttl | 67 +- tests/testconfig-nograph.ttl | 0 tests/testconfig.inc | 3 - tests/testconfig.ttl | 463 ++ view/about.inc.dist | 2 +- view/about.twig | 12 +- view/changes.twig | 8 +- view/concept-shared.twig | 200 +- view/feedback.twig | 3 +- view/group-contents.twig | 6 + view/group-index.twig | 6 + view/headerbar.twig | 10 +- view/light.twig | 69 +- view/scripts.twig | 32 +- view/search-result.twig | 50 +- view/topbar.twig | 6 +- view/vocab-search-listing.twig | 3 +- view/vocab-shared.twig | 61 +- view/vocab.twig | 5 + view/vocabularylist.twig | 4 +- 279 files changed, 17319 insertions(+), 4861 deletions(-) create mode 100644 .sonarcloud.properties create mode 100644 Dockerfile create mode 100644 Vagrantfile create mode 100644 ansible.cfg create mode 100644 ansible/playbook.yml create mode 100644 ansible/roles/base/tasks/main.yml create mode 100644 ansible/roles/fuseki/files/fuseki create mode 100644 ansible/roles/fuseki/files/skosmos.ttl create mode 100644 ansible/roles/fuseki/tasks/main.yml create mode 100644 ansible/roles/openjdk/tasks/main.yml create mode 100644 ansible/roles/skosmos/files/000-default.conf create mode 100644 ansible/roles/skosmos/files/config.ttl create mode 100644 ansible/roles/skosmos/tasks/main.yml delete mode 100644 config.inc.dist create mode 100644 config.ttl.dist create mode 100644 docker-compose.yml create mode 100644 migrate-config.php create mode 100644 model/BaseConfig.php create mode 100644 model/LabelSkosXL.php create mode 100644 model/Modifiable.php create mode 100644 model/resolver/LOCResource.php create mode 100644 model/resolver/LinkedDataResource.php create mode 100644 model/resolver/RemoteResource.php create mode 100644 model/resolver/Resolver.php create mode 100644 model/resolver/WDQSResource.php create mode 100644 resource/fonts/eot/FiraMono-Medium.eot create mode 100644 resource/fonts/eot/FiraSans-Book.eot create mode 100644 resource/fonts/eot/FiraSans-BookItalic.eot create mode 100644 resource/fonts/eot/FiraSans-Eight.eot create mode 100644 resource/fonts/eot/FiraSans-EightItalic.eot create mode 100644 resource/fonts/eot/FiraSans-ExtraBold.eot create mode 100644 resource/fonts/eot/FiraSans-ExtraBoldItalic.eot create mode 100644 resource/fonts/eot/FiraSans-ExtraLight.eot create mode 100644 resource/fonts/eot/FiraSans-ExtraLightItalic.eot create mode 100644 resource/fonts/eot/FiraSans-Four.eot create mode 100644 resource/fonts/eot/FiraSans-FourItalic.eot create mode 100644 resource/fonts/eot/FiraSans-Hair.eot create mode 100644 resource/fonts/eot/FiraSans-HairItalic.eot create mode 100644 resource/fonts/eot/FiraSans-Heavy.eot create mode 100644 resource/fonts/eot/FiraSans-HeavyItalic.eot create mode 100644 resource/fonts/eot/FiraSans-Italic.eot create mode 100644 resource/fonts/eot/FiraSans-SemiBold.eot create mode 100644 resource/fonts/eot/FiraSans-SemiBoldItalic.eot create mode 100644 resource/fonts/eot/FiraSans-Thin.eot create mode 100644 resource/fonts/eot/FiraSans-ThinItalic.eot create mode 100644 resource/fonts/eot/FiraSans-Two.eot create mode 100644 resource/fonts/eot/FiraSans-TwoItalic.eot create mode 100644 resource/fonts/eot/FiraSans-Ultra.eot create mode 100644 resource/fonts/eot/FiraSans-UltraItalic.eot create mode 100644 resource/fonts/eot/FiraSans-UltraLight.eot create mode 100644 resource/fonts/eot/FiraSans-UltraLightItalic.eot create mode 100644 resource/fonts/ttf/FiraMono-Medium.ttf create mode 100644 resource/fonts/ttf/FiraSans-Book.ttf create mode 100644 resource/fonts/ttf/FiraSans-BookItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-Eight.ttf create mode 100644 resource/fonts/ttf/FiraSans-EightItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-ExtraBold.ttf create mode 100644 resource/fonts/ttf/FiraSans-ExtraBoldItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-ExtraLight.ttf create mode 100644 resource/fonts/ttf/FiraSans-ExtraLightItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-Four.ttf create mode 100644 resource/fonts/ttf/FiraSans-FourItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-Hair.ttf create mode 100644 resource/fonts/ttf/FiraSans-HairItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-Heavy.ttf create mode 100644 resource/fonts/ttf/FiraSans-HeavyItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-Italic.ttf create mode 100644 resource/fonts/ttf/FiraSans-SemiBold.ttf create mode 100644 resource/fonts/ttf/FiraSans-SemiBoldItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-Thin.ttf create mode 100644 resource/fonts/ttf/FiraSans-ThinItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-Two.ttf create mode 100644 resource/fonts/ttf/FiraSans-TwoItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-Ultra.ttf create mode 100644 resource/fonts/ttf/FiraSans-UltraItalic.ttf create mode 100644 resource/fonts/ttf/FiraSans-UltraLight.ttf create mode 100644 resource/fonts/ttf/FiraSans-UltraLightItalic.ttf create mode 100644 resource/fonts/woff/FiraMono-Medium.woff create mode 100644 resource/fonts/woff/FiraSans-Book.woff create mode 100644 resource/fonts/woff/FiraSans-BookItalic.woff create mode 100644 resource/fonts/woff/FiraSans-Eight.woff create mode 100644 resource/fonts/woff/FiraSans-EightItalic.woff create mode 100644 resource/fonts/woff/FiraSans-ExtraBold.woff create mode 100644 resource/fonts/woff/FiraSans-ExtraBoldItalic.woff create mode 100644 resource/fonts/woff/FiraSans-ExtraLight.woff create mode 100644 resource/fonts/woff/FiraSans-ExtraLightItalic.woff create mode 100644 resource/fonts/woff/FiraSans-Four.woff create mode 100644 resource/fonts/woff/FiraSans-FourItalic.woff create mode 100644 resource/fonts/woff/FiraSans-Hair.woff create mode 100644 resource/fonts/woff/FiraSans-HairItalic.woff create mode 100644 resource/fonts/woff/FiraSans-Heavy.woff create mode 100644 resource/fonts/woff/FiraSans-HeavyItalic.woff create mode 100644 resource/fonts/woff/FiraSans-Italic.woff create mode 100644 resource/fonts/woff/FiraSans-SemiBold.woff create mode 100644 resource/fonts/woff/FiraSans-SemiBoldItalic.woff create mode 100644 resource/fonts/woff/FiraSans-Thin.woff create mode 100644 resource/fonts/woff/FiraSans-ThinItalic.woff create mode 100644 resource/fonts/woff/FiraSans-Two.woff create mode 100644 resource/fonts/woff/FiraSans-TwoItalic.woff create mode 100644 resource/fonts/woff/FiraSans-Ultra.woff create mode 100644 resource/fonts/woff/FiraSans-UltraItalic.woff create mode 100644 resource/fonts/woff/FiraSans-UltraLight.woff create mode 100644 resource/fonts/woff/FiraSans-UltraLightItalic.woff delete mode 100644 resource/js/jquery.mCustomScrollbar.min.js delete mode 100644 resource/js/jquery.mousewheel.min.js delete mode 100644 resource/js/jquery.qtip.min.js delete mode 100644 resource/js/lscache.min.js delete mode 100644 resource/js/waypoints.min.js create mode 100644 resource/pics/type.gif create mode 100644 resource/translations/ar/LC_MESSAGES/skosmos.mo create mode 100644 resource/translations/da/LC_MESSAGES/skosmos.mo create mode 100644 resource/translations/fa/LC_MESSAGES/skosmos.mo create mode 100644 resource/translations/nl/LC_MESSAGES/skosmos.mo create mode 100644 resource/translations/pt/LC_MESSAGES/skosmos.mo create mode 100644 resource/translations/pt_BR/LC_MESSAGES/skosmos.mo create mode 100644 resource/translations/ru/LC_MESSAGES/skosmos.mo create mode 100755 resource/translations/skosmos_ar.po create mode 100644 resource/translations/skosmos_da.po create mode 100644 resource/translations/skosmos_fa.po create mode 100644 resource/translations/skosmos_nl.po create mode 100644 resource/translations/skosmos_pt.po create mode 100644 resource/translations/skosmos_pt_BR.po create mode 100644 resource/translations/skosmos_ru.po create mode 100644 tests/Http304Test.php create mode 100644 tests/ResolverTest.php create mode 100644 tests/RestControllerTest.php create mode 100644 tests/WebControllerTest.php mode change 100644 => 100755 tests/fuseki-assembler.ttl delete mode 100644 tests/jenatestconfig.inc rename tests/{testvocabularies.ttl => jenatestconfig.ttl} (54%) create mode 100644 tests/test-vocab-data/cbd.ttl create mode 100644 tests/test-vocab-data/http304.ttl create mode 100644 tests/test-vocab-data/marc-fi.mrcx create mode 100644 tests/test-vocab-data/marc-sv.mrcx create mode 100644 tests/test-vocab-data/marc-undefined.mrcx create mode 100644 tests/test-vocab-data/myns-ontology.ttl create mode 100644 tests/test-vocab-data/test-concept-schemes.ttl create mode 100644 tests/test-vocab-data/test-marc.ttl create mode 100644 tests/test-vocab-data/test-notation-sort.ttl create mode 100644 tests/test-vocab-data/test-qualified-broader.ttl create mode 100644 tests/test-vocab-data/test-qualified-notation.ttl create mode 100644 tests/test-vocab-data/xl.ttl rename vocabularies.ttl.dist => tests/testconfig-fordefaults.ttl (52%) create mode 100644 tests/testconfig-nograph.ttl delete mode 100644 tests/testconfig.inc create mode 100644 tests/testconfig.ttl diff --git a/.codeclimate.yml b/.codeclimate.yml index faa9ee872..93fd8eb53 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -38,8 +38,7 @@ exclude_paths: - LICENSE - README.md - composer.json -- config.inc.dist -- vocabularies.ttl.dist +- config.ttl.dist - favicon.ico - phpdoc.sh - phpunit.xml diff --git a/.gitignore b/.gitignore index 2c3d730c5..c318eef69 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,13 @@ -config.inc -vocabularies.ttl +config.ttl +build vendor report components +plugins/* +!README composer.phar composer.lock +tests/jena-fuseki* +.vagrant +.project +.DS_Store diff --git a/.jshintrc b/.jshintrc index e3abf5997..47355d444 100644 --- a/.jshintrc +++ b/.jshintrc @@ -9,11 +9,7 @@ "loadPage": false, "Bloodhound": false, "Handlebars": false, - "getUrlParams": false, - "createCookie": false, - "debounce": false, - "readCookie": false, - "noResultsTranslation": false, + "noResultsTranslation": false, "lscache": false, "getTreeConfiguration": false, "invokeParentTree": false, diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 000000000..7a93b07aa --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1,15 @@ +# Path to sources +#sonar.sources=. +#sonar.exclusions= +#sonar.inclusions= + +# Path to tests +#sonar.tests= +#sonar.test.exclusions= +#sonar.test.inclusions= + +# Source encoding +#sonar.sourceEncoding=UTF-8 + +# Exclusions for copy-paste detection +#sonar.cpd.exclusions= diff --git a/.travis.yml b/.travis.yml index ed7ffc09a..d75cd7a69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,29 +2,47 @@ sudo: required dist: trusty language: php php: - - "5.6" + - 7.1 + - 7.2 + - 7.3 + - 7.4 install: + - phpenv config-rm xdebug.ini - composer install cache: directories: - $HOME/.composer - vendor before_script: + - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter + - chmod +x ./cc-test-reporter + - ./cc-test-reporter before-build - cd tests + - export LANGUAGE=fr - sh ./init_fuseki.sh - cd .. +script: + - phpdbg -qrr vendor/bin/phpunit after_script: + - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT + - bash <(curl -s https://codecov.io/bash) - pkill -f 'java -Xmx1200M -jar' - - vendor/bin/test-reporter --stdout > codeclimate.json - - "curl -X POST -d @codeclimate.json -H 'Content-Type: application/json' -H 'User-Agent: Code Climate (PHP Test Reporter v0.1.1)' https://codeclimate.com/test_reports" -addons: - code_climate: - repo_token: fb98170a5c7ea9cc2bbab19ff26268335e6a11a4f8267ca935e5e8ff4624886c env: - - FUSEKI_VERSION=3.4.0 - - FUSEKI_VERSION=SNAPSHOT + global: + - CC_TEST_REPORTER_ID=fb98170a5c7ea9cc2bbab19ff26268335e6a11a4f8267ca935e5e8ff4624886c + matrix: + - FUSEKI_VERSION=3.14.0 + - FUSEKI_VERSION=SNAPSHOT matrix: + exclude: + - php: 7.1 + env: FUSEKI_VERSION=SNAPSHOT + - php: 7.2 + env: FUSEKI_VERSION=SNAPSHOT + - php: 7.4 + env: FUSEKI_VERSION=SNAPSHOT allow_failures: + - php: 7.4 - env: FUSEKI_VERSION=SNAPSHOT notifications: - slack: finto:5rO9Lp4Tstn6y34grtFBpjJ0 + slack: kansalliskirjasto:9mOKu3Vws1CIddF5jqWgXbli diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..26f25b3f6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM php:7.3-apache + +RUN apt-get update && \ + apt-get -y install locales && \ + for locale in en_GB en_US fi_FI fr_FR sv_SE; do \ + echo "${locale}.UTF-8 UTF-8" >> /etc/locale.gen ; \ + done && \ + locale-gen + +RUN a2enmod rewrite +RUN docker-php-ext-install gettext diff --git a/README.md b/README.md index 32491a4e5..4f179d790 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/NatLibFi/Skosmos/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/NatLibFi/Skosmos/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/ca1939e4-919d-4429-95e7-d63e0a35f9a1/mini.png)](https://insight.sensiolabs.com/projects/ca1939e4-919d-4429-95e7-d63e0a35f9a1) [![Codacy Badge](https://api.codacy.com/project/badge/grade/c41550cd00fe4962ba766f8b5fe4a5ff)](https://www.codacy.com/app/NatLibFi/Skosmos) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=NatLibFi_Skosmos&metric=alert_status)](https://sonarcloud.io/dashboard?id=NatLibFi_Skosmos) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/NatLibFi/Skosmos.svg)](http://isitmaintained.com/project/NatLibFi/Skosmos "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/NatLibFi/Skosmos.svg)](http://isitmaintained.com/project/NatLibFi/Skosmos "Percentage of issues still open") @@ -26,7 +27,7 @@ The latest development version is also available at Skosmos is implemented using PHP, with Twig templates and e.g. jQuery and jsTree used to build the web interface, and EasyRdf for SPARQL and RDF data -access. We use [BrowserStack](https://www.browserstack.com) for making sure Skosmos works consistently with different browsers. +access. The code is open source under the MIT license. See [Installation](https://github.com/NatLibFi/Skosmos/wiki/Installation) in the @@ -35,7 +36,6 @@ wiki for details on obtaining the source and running your own instance of Skosmo For information about released versions, see [Release Notes](https://github.com/NatLibFi/Skosmos/releases). -Skosmos was formerly known as ONKI Light. ## Reporting issues diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 000000000..734b9da6a --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,27 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + + config.vm.box = "ubuntu/xenial64" + config.vm.network "forwarded_port", guest: 80, host: 8010 + config.vm.network "forwarded_port", guest: 3030, host: 3030 + config.vm.post_up_message = "Skosmos up and running at localhost:8010/Skosmos, Fuseki at localhost:3030" + + config.vm.synced_folder "", "/var/www/html/Skosmos" + + config.vm.provider "virtualbox" do |vb| + vb.memory = "4096" + vb.cpus = "2" + # disable creating a log file to root folder: + vb.customize [ "modifyvm", :id, "--uartmode1", "disconnected" ] + end + + config.vm.provision "ansible" do |ansible| + ansible.playbook = "ansible/playbook.yml" + ansible.extra_vars = { ansible_python_interpreter:"/usr/bin/python3" } + ansible.verbose = "v" + ansible.compatibility_mode = "2.0" + end + +end diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 000000000..1ec2ff061 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] + +retry_files_enabled = False diff --git a/ansible/playbook.yml b/ansible/playbook.yml new file mode 100644 index 000000000..84a80b501 --- /dev/null +++ b/ansible/playbook.yml @@ -0,0 +1,13 @@ +--- +- hosts: all + become: True + gather_facts: False + roles: + - base + - openjdk + - fuseki + - skosmos + pre_tasks: + - name: Install Unzip for Ansible + raw: sudo apt-get install unzip + - setup: # aka gather_facts diff --git a/ansible/roles/base/tasks/main.yml b/ansible/roles/base/tasks/main.yml new file mode 100644 index 000000000..d84684847 --- /dev/null +++ b/ansible/roles/base/tasks/main.yml @@ -0,0 +1,5 @@ + +- name: Add 'openjdk' repository + apt_repository: + repo: ppa:openjdk-r/ppa + state: present diff --git a/ansible/roles/fuseki/files/fuseki b/ansible/roles/fuseki/files/fuseki new file mode 100644 index 000000000..d755b9aa7 --- /dev/null +++ b/ansible/roles/fuseki/files/fuseki @@ -0,0 +1,5 @@ +export FUSEKI_HOME=/opt/fuseki +export FUSEKI_BASE=/etc/fuseki + +FUSEKI_USER=fuseki +JAVA_OPTIONS="-Xmx2048M" diff --git a/ansible/roles/fuseki/files/skosmos.ttl b/ansible/roles/fuseki/files/skosmos.ttl new file mode 100644 index 000000000..a625cf927 --- /dev/null +++ b/ansible/roles/fuseki/files/skosmos.ttl @@ -0,0 +1,58 @@ +@prefix : . +@prefix tdb: . +@prefix rdf: . +@prefix ja: . +@prefix rdfs: . +@prefix fuseki: . +@prefix text: . +@prefix skos: . + +:service_tdb_all a fuseki:Service ; + rdfs:label "TDB+text skosmos" ; + fuseki:dataset :text_dataset ; + fuseki:name "skosmos" ; + fuseki:serviceQuery "query" , "sparql" ; + fuseki:serviceReadGraphStore "get" ; + fuseki:serviceReadWriteGraphStore + "data" ; + fuseki:serviceUpdate "update" ; + fuseki:serviceUpload "upload" . + +:text_dataset a text:TextDataset ; + text:dataset :tdb_dataset_readwrite ; +# tdb:unionDefaultGraph true ; + text:index :index_lucene . + +:tdb_dataset_readwrite + a tdb:DatasetTDB ; + tdb:location "/etc/fuseki/databases/skosmos" . + +:index_lucene a text:TextIndexLucene ; + text:directory ; + text:entityMap :entity_map ; + text:storeValues true . + +# Text index configuration for Skosmos 1.4 and above (requires Fuseki 1.3.0+ or 2.3.0+) +:entity_map a text:EntityMap ; + text:entityField "uri" ; + text:graphField "graph" ; + text:defaultField "pref" ; + text:uidField "uid" ; + text:langField "lang" ; + text:map ( + # skos:prefLabel + [ text:field "pref" ; + text:predicate skos:prefLabel ; + text:analyzer [ a text:LowerCaseKeywordAnalyzer ] + ] + # skos:altLabel + [ text:field "alt" ; + text:predicate skos:altLabel ; + text:analyzer [ a text:LowerCaseKeywordAnalyzer ] + ] + # skos:hiddenLabel + [ text:field "hidden" ; + text:predicate skos:hiddenLabel ; + text:analyzer [ a text:LowerCaseKeywordAnalyzer ] + ] + ) . diff --git a/ansible/roles/fuseki/tasks/main.yml b/ansible/roles/fuseki/tasks/main.yml new file mode 100644 index 000000000..f5b15a938 --- /dev/null +++ b/ansible/roles/fuseki/tasks/main.yml @@ -0,0 +1,145 @@ + +- name: Download Fuseki tarball + get_url: + url: https://archive.apache.org/dist/jena/binaries/apache-jena-fuseki-3.8.0.tar.gz + dest: /home/vagrant/ + mode: 755 + +- name: Extract Fuseki to opt/ + command: chdir=/opt /bin/tar xzf /home/vagrant/apache-jena-fuseki-3.8.0.tar.gz + args: + warn: false + +- name: Create a symbolic link to /opt/fuseki + file: + src: /opt/apache-jena-fuseki-3.8.0 + dest: /opt/fuseki + state: link + +- name: Add a new user fuseki + user: + name: fuseki + home: /opt/fuseki + system: yes + create_home: no + +- name: Create directories to /var/lib + file: + path: "/var/lib/fuseki/{{ item }}" + state: directory + owner: fuseki + group: fuseki + mode: 0775 + with_items: + - backups + - databases + - system + - system_files + +- name: Create directories + file: + path: "{{ item }}" + state: directory + owner: fuseki + group: fuseki + mode: 0775 + with_items: + - /var/log/fuseki + - /etc/fuseki + +- name: Link fuseki home + file: + src: "/var/lib/fuseki/{{ item }}" + dest: /etc/fuseki/{{ item }} + state: link + with_items: + - backups + - databases + - system + - system_files + +- name: Link logs to /etc/fuseki/logs + file: + src: /var/log/fuseki + dest: /etc/fuseki/logs + state: link + +- name: Copy Fuseki config + copy: + src: files/fuseki + dest: /etc/default/ + +- name: Setup autostart + command: chdir=/etc/init.d ln -s /opt/fuseki/fuseki . + args: + warn: false + ignore_errors: yes + +- name: Update services + command: update-rc.d fuseki defaults + +- name: Start service Fuseki + service: + name: fuseki + state: started + +- name: Create Skosmos database + uri: + url: http://localhost:3030/$/datasets/ + method: POST + body: dbName=skosmos&dbType=tdb + body_format: raw + +- name: Shut down service Fuseki for configuration + service: + name: fuseki + state: stopped + +- name: Create configuration directory for Skosmos datasets + file: + path: etc/fuseki/configuration + state: directory + +- name: Create text index for Skosmos datasets + copy: + src: files/skosmos.ttl + dest: etc/fuseki/configuration/skosmos.ttl + +- name: Allow management operations for non-localhost access + lineinfile: + path: /etc/fuseki/shiro.ini + line: "/$/** = anon" + +- name: Start service Fuseki + service: + name: fuseki + state: started + +- name: Install Ruby + apt: + name: ruby + update_cache: yes + state: present + +- name: Download example vocabulary data (STW Thesaurus) + get_url: + url: http://zbw.eu/stw/version/latest/download/stw.ttl.zip + dest: /home/vagrant/ + mode: 755 + +- name: Unzip STW Thesaurus data file + command: unzip /home/vagrant/stw.ttl.zip -d /home/vagrant/ + args: + warn: false + +- name: Download example vocabulary data (UNESCO Thesaurus) + get_url: + url: http://skos.um.es/unescothes/unescothes.ttl + dest: /home/vagrant/ + mode: 755 + +- name: Load example vocabulary data (STW Thesaurus) + command: /opt/fuseki/bin/s-put http://localhost:3030/skosmos/data http://zbw.eu/stw/ /home/vagrant/stw.ttl + +- name: Load example vocabulary data (UNESCO Thesaurus) + command: /opt/fuseki/bin/s-put http://localhost:3030/skosmos/data http://skos.um.es/unescothes/ /home/vagrant/unescothes.ttl diff --git a/ansible/roles/openjdk/tasks/main.yml b/ansible/roles/openjdk/tasks/main.yml new file mode 100644 index 000000000..8e6c05481 --- /dev/null +++ b/ansible/roles/openjdk/tasks/main.yml @@ -0,0 +1,5 @@ +- name: Update apt-cache and then install openjdk-8-jre + apt: + name: openjdk-8-jre + update_cache: yes + state: present diff --git a/ansible/roles/skosmos/files/000-default.conf b/ansible/roles/skosmos/files/000-default.conf new file mode 100644 index 000000000..5f9df44a4 --- /dev/null +++ b/ansible/roles/skosmos/files/000-default.conf @@ -0,0 +1,16 @@ + + + + Options Indexes FollowSymLinks MultiViews + AllowOverride All + Order allow,deny + allow from all + + + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + + diff --git a/ansible/roles/skosmos/files/config.ttl b/ansible/roles/skosmos/files/config.ttl new file mode 100644 index 000000000..6239cf89f --- /dev/null +++ b/ansible/roles/skosmos/files/config.ttl @@ -0,0 +1,157 @@ +@prefix void: . +@prefix rdf: . +@prefix rdfs: . +@prefix owl: . +@prefix xsd: . +@prefix dc: . +@prefix foaf: . +@prefix wv: . +@prefix sd: . +@prefix skos: . +@prefix skosmos: . +@prefix isothes: . +@prefix mdrtype: . +@prefix : <#> . + +# Skosmos main configuration + +:config a skosmos:Configuration ; + # SPARQL endpoint + # a local Fuseki server is usually on localhost:3030 + # skosmos:sparqlEndpoint ; + skosmos:sparqlEndpoint ; + # use the dev.finto.fi endpoint where the example vocabularies reside + # skosmos:sparqlEndpoint ; + # sparql-query extension, or "Generic" for plain SPARQL 1.1 + # set to "JenaText" instead if you use Fuseki with jena-text index + # skosmos:sparqlDialect "Generic" ; + skosmos:sparqlDialect "JenaText" ; + # whether to enable collation in sparql queries + skosmos:sparqlCollationEnabled false ; + # HTTP client configuration + skosmos:sparqlTimeout 20 ; + skosmos:httpTimeout 5 ; + # customize the service name + skosmos:serviceName "Skosmos" ; + # customize the base element. Set this if the automatic base url detection doesn't work. For example setups behind a proxy. + # skosmos:baseHref "http://localhost/Skosmos/" ; + # interface languages available, and the corresponding system locales + skosmos:languages ( + # [ rdfs:label "fi" ; rdf:value "fi_FI.utf8" ] + # [ rdfs:label "sv" ; rdf:value "sv_SE.utf8" ] + [ rdfs:label "en" ; rdf:value "en_GB.utf8" ] + [ rdfs:label "de" ; rdf:value "de_DE.utf8" ] + ) ; + # how many results (maximum) to load at a time on the search results page + skosmos:searchResultsSize 20 ; + # how many items (maximum) to retrieve in transitive property queries + skosmos:transitiveLimit 1000 ; + # whether or not to log caught exceptions + skosmos:logCaughtExceptions false ; + # set to TRUE to enable logging into browser console + skosmos:logBrowserConsole false ; + # set to a logfile path to enable logging into log file + # skosmos:logFileName "" ; + # a default location for Twig template rendering + skosmos:templateCache "/tmp/skosmos-template-cache" ; + # customize the css by adding your own stylesheet + skosmos:customCss "resource/css/stylesheet.css" ; + # default email address where to send the feedback + skosmos:feedbackAddress "" ; + # email address to set as the sender for feedback messages + skosmos:feedbackSender "" ; + # email address to set as the envelope sender for feedback messages + skosmos:feedbackEnvelopeSender "" ; + # whether to display the ui language selection as a dropdown (useful for cases where there are more than 3 languages) + skosmos:uiLanguageDropdown false ; + # whether to enable the spam honey pot or not, enabled by default + skosmos:uiHoneypotEnabled true ; + # default time a user must wait before submitting a form + skosmos:uiHoneypotTime 5 ; + # plugins to activate for the whole installation (including all vocabularies) + skosmos:globalPlugins () . + +# Skosmos vocabularies + +# :ysa a skosmos:Vocabulary, void:Dataset ; +# dc:title "YSA - Yleinen suomalainen asiasanasto"@fi, +# "YSA - Allmän tesaurus på finska"@sv, +# "YSA - General Finnish thesaurus"@en ; +# dc:subject :cat_general ; +# dc:type mdrtype:THESAURUS ; +# void:uriSpace "http://www.yso.fi/onto/ysa/"; +# skosmos:groupClass skos:Collection; +# skosmos:language "fi"; +# skosmos:shortName "YSA"; +# skosmos:feedbackRecipient "vesa-posti@helsinki.fi" ; +# skosmos:showChangeList "true" ; +# void:dataDump ; +# void:sparqlEndpoint ; +# skosmos:sparqlGraph +# . + +# :yso a skosmos:Vocabulary, void:Dataset ; +# dc:title "YSO - Yleinen suomalainen ontologia"@fi, +# "ALLFO - Allmän finländsk ontologi"@sv, +# "YSO - General Finnish ontology"@en ; +# dc:subject :cat_general ; +# dc:type mdrtype:ONTOLOGY ; +# void:uriSpace "http://www.yso.fi/onto/yso/"; +# skosmos:language "fi", "sv", "en"; +# skosmos:defaultLanguage "fi"; +# skosmos:showTopConcepts "true"; +# skosmos:showStatistics "false"; +# skosmos:loadExternalResources "false"; +# skosmos:shortName "YSO", +# "ALLFO"@sv; +# skosmos:groupClass isothes:ConceptGroup ; +# skosmos:arrayClass isothes:ThesaurusArray ; +# void:dataDump ; +# void:sparqlEndpoint ; +# skosmos:sparqlGraph ; +# skosmos:mainConceptScheme +# . + +:unesco a skosmos:Vocabulary, void:Dataset ; + dc:title "UNESCO Thesaurus"@en ; + skosmos:shortName "UNESCO"; + dc:subject :cat_general ; + void:uriSpace "http://skos.um.es/unescothes/"; + skosmos:language "en", "es", "fr", "ru"; + skosmos:defaultLanguage "en"; + skosmos:showTopConcepts true ; + skosmos:groupClass isothes:ConceptGroup ; + void:sparqlEndpoint ; + skosmos:sparqlGraph +. + +:stw a skosmos:Vocabulary, void:Dataset ; + dc:title "STW Thesaurus for Economics"@en ; + skosmos:shortName "STW"; + dc:subject :cat_general ; + void:uriSpace "http://zbw.eu/stw/"; + skosmos:language "en", "de"; + skosmos:defaultLanguage "de"; + void:sparqlEndpoint ; + skosmos:sparqlGraph +. + +:categories a skos:ConceptScheme; + skos:prefLabel "Skosmos Vocabulary Categories"@en +. + +:cat_general a skos:Concept ; + skos:topConceptOf :categories ; + skos:inScheme :categories ; + skos:prefLabel "Yleiskäsitteet"@fi, + "Allmänna begrepp"@sv, + "General concepts"@en +. + +mdrtype:THESAURUS a skos:Concept ; + skos:prefLabel "Тезаурус"@bg, "Tezaurus"@cs, "Tesaurus"@da, "Thesaurus"@de, "Θησαυρός"@el, "Thesaurus"@en, "Tesaurus"@et, "Tesaurus"@fi, "Thésaurus"@fr, "Pojmovnik"@hr, "Tezaurusz"@hu, "Tesauro"@it, "Tēzaurs"@lv, "Tezauras"@lt, "Teżawru"@mt, "Thesaurus"@nl, "Tesaurus"@no, "Tezaurus"@pl, "Tesauro"@pt, "Tezaur"@ro, "Synonymický slovník"@sk, "Tezaver"@sl, "Tesauro"@es, "Tesaurus"@sv +. + +mdrtype:ONTOLOGY a skos:Concept ; + skos:prefLabel "Онтология"@bg, "Ontologie"@cs, "Ontologi"@da, "Ontologie"@de, "Οντολογία"@el, "Ontology"@en, "Ontoloogia"@et, "Ontologia"@fi, "Ontologie"@fr, "Ontologija"@hr, "Ontológia"@hu, "Ontologia"@it, "Ontoloģija"@lv, "Ontologija"@lt, "Ontoloġija"@mt, "Ontologie"@nl, "Ontologi"@no, "Struktura pojęciowa"@pl, "Ontologia"@pt, "Ontologie"@ro, "Ontológia"@sk, "Ontologija"@sl, "Ontología"@es, "Ontologi"@sv +. diff --git a/ansible/roles/skosmos/tasks/main.yml b/ansible/roles/skosmos/tasks/main.yml new file mode 100644 index 000000000..0d900dca2 --- /dev/null +++ b/ansible/roles/skosmos/tasks/main.yml @@ -0,0 +1,64 @@ + +- name: Update apt cache + become: true + apt: + update_cache: yes + +- name: Install required Skosmos dependencies + apt: + name: "{{ item }}" + state: present + with_items: + - apache2 + - libapache2-mod-php7.0 + - php-xml + - php-mbstring + - git + +- name: Copy modified Apache configuration file + copy: + src: files/000-default.conf + dest: /etc/apache2/sites-enabled/000-default.conf + +- name: Enable Apache module mod_rewrite + command: a2enmod rewrite + +- name: Restart Apache + service: + name: apache2 + state: restarted + +- name: Download composer + get_url: + url: https://getcomposer.org/installer + dest: /home/vagrant/composer-installer + +- name: Install composer + shell: cat /home/vagrant/composer-installer | php -- --install-dir=/usr/local/bin + +- name: Rename composer.phar to composer + shell: mv /usr/local/bin/composer.phar /usr/local/bin/composer + args: + creates: /usr/local/bin/composer + +- name: Make composer executable + file: + path: /usr/local/bin/composer + mode: a+x + state: file + +- name: Install Skosmos PHP Dependencies + command: chdir=/var/www/html/Skosmos composer install + +- name: Copy global and vocabulary-specific configurations + copy: + src: files/config.ttl + dest: /var/www/html/Skosmos/config.ttl + +- name: Generate locales, if necessary + shell: "locale-gen {{ item }}" + with_items: + - en_GB.utf8 + - de_DE.utf8 + # - fi_FI.utf8 + # - sv_SE.utf8 diff --git a/composer.json b/composer.json index 60a80f8a1..a498d3092 100644 --- a/composer.json +++ b/composer.json @@ -8,11 +8,35 @@ "type": "package", "package": { "name": "medialize/uri.js", - "version": "1.18.2", + "version": "1.19.0", "source": { "url": "https://github.com/medialize/URI.js.git", "type": "git", - "reference": "v1.18.2" + "reference": "v1.19.0" + } + } + }, + "lscache": { + "type": "package", + "package": { + "name": "pamelafox/lscache", + "version": "1.0.5", + "source": { + "url": "https://github.com/pamelafox/lscache.git", + "type": "git", + "reference": "1.0.5" + } + } + }, + "malihu-custom-scrollbar": { + "type": "package", + "package": { + "name": "malihu/malihu-custom-scrollbar-plugin", + "version": "3.1.5", + "source": { + "url": "https://github.com/malihu/malihu-custom-scrollbar-plugin.git", + "type": "git", + "reference": "3.1.5" } } }, @@ -30,30 +54,36 @@ } }, "require": { - "components/jquery": "1.12.*", + "components/jquery": "2.2.*", "components/jqueryui": "1.12.*", - "components/handlebars.js": "v1.3.0", + "components/handlebars.js": "v4.7.6", "davidstutz/bootstrap-multiselect": "v0.9.13", "easyrdf/easyrdf": "0.10.0-alpha.1", - "twig/twig": "1.29.*", - "twig/extensions": "1.4.*", - "twitter/bootstrap": "3.2.*", + "etdsolutions/waypoints": "4.0.0", + "twig/twig": "2.13.*", + "twig/extensions": "1.5.*", + "twitter/bootstrap": "3.3.*", "twitter/typeahead.js": "v0.10.5", - "willdurand/negotiation": "1.5.*", + "willdurand/negotiation": "2.3.*", "vakata/jstree": "3.3.*", - "punic/punic": "1.6.0", + "punic/punic": "3.5.1", "ml/json-ld": "1.*", - "medialize/uri.js": "1.18.2", + "medialize/uri.js": "1.19.0", "ext-gettext": "*", - "monolog/monolog": "^1.22" + "ext-intl": "*", + "ext-mbstring": "*", + "ext-xsl": "*", + "monolog/monolog": "1.23.*", + "newerton/jquery-mousewheel": "dev-master", + "pamelafox/lscache": "1.0.5", + "malihu/malihu-custom-scrollbar-plugin": "3.1.5", + "grimmlink/qtip2": "3.0.3" }, "require-dev": { - "phpunit/phpunit": "4.8 - 5.1", - "umpirsky/twig-gettext-extractor": "1.1.*", - "phpdocumentor/phpdocumentor": "2.*", - "codeclimate/php-test-reporter": "0.3.2", - "symfony/dom-crawler": "3.2.6", - "mockery/mockery": "1.0.0-alpha1" + "phpunit/phpunit": "7.2.0 - 7.5.20", + "umpirsky/twig-gettext-extractor": "1.3.*", + "symfony/dom-crawler": "3.4.3", + "mockery/mockery": "1.3.1" }, "autoload": { "classmap": ["controller/", "model/", "model/sparql/"] diff --git a/config.inc.dist b/config.inc.dist deleted file mode 100644 index d792b8ea8..000000000 --- a/config.inc.dist +++ /dev/null @@ -1,71 +0,0 @@ - 'fi_FI.utf8', - 'sv' => 'sv_SE.utf8', - 'en' => 'en_GB.utf8' -); - -// default SPARQL endpoint -// a local Fuseki server is usually on localhost:3030 -define("DEFAULT_ENDPOINT", "http://localhost:3030/ds/sparql"); - -// how many results (maximum) to load at a time on the search results page -define("SEARCH_RESULTS_SIZE", 20); - -// how many items (maximum) to retrieve in transitive property queries -define("DEFAULT_TRANSITIVE_LIMIT", 1000); - -// a default location for Twig template rendering -define("TEMPLATE_CACHE", "/tmp/skosmos-template-cache"); - -// default sparql-query extension, or "Generic" for plain SPARQL 1.1 -// set to "JenaText" instead if you use Fuseki with jena-text index -define("DEFAULT_SPARQL_DIALECT", "Generic"); - -// default email address to send the feedback -define("FEEDBACK_ADDRESS", ""); - -// email address to set as the envelope sender for feedback messages -define("FEEDBACK_ENVELOPE_SENDER", ""); - -// whether or not to log caught exceptions -define ("LOG_CAUGHT_EXCEPTIONS", FALSE); - -// set to TRUE to enable logging into browser console -define ("LOG_BROWSER_CONSOLE", FALSE); - -// set to a logfile path to enable logging into log file -define ("LOG_FILE_NAME", NULL); - -# customize the service name -define("SERVICE_NAME", "Skosmos"); - -// customize the service logo by pointing to your logo here. -define("SERVICE_LOGO", "./resource/pics/logo.png"); - -// customize the css by adding your own stylesheet -define("CUSTOM_CSS", "resource/css/stylesheet.css"); - -// Customize the base element. Set this if the automatic base url detection doesn't work. For example setups behind a proxy. -// define("BASE_HREF", "http://localhost/Skosmos/"); - -// whether to display the ui language selection as a dropdown (useful for cases where there are more than 3 languages) -define("UI_LANGUAGE_DROPDOWN", FALSE); - -// whether to enable the spam honey pot or not, enabled by default -define("UI_HONEYPOT_ENABLED", TRUE); - -// default time a user must wait before submitting a form -define("UI_HONEYPOT_TIME", 5); - -// whether to enable collation in sparql queries -define("SPARQL_COLLATION_ENABLED", FALSE); diff --git a/config.ttl.dist b/config.ttl.dist new file mode 100644 index 000000000..b1b191b45 --- /dev/null +++ b/config.ttl.dist @@ -0,0 +1,130 @@ +@prefix void: . +@prefix rdf: . +@prefix rdfs: . +@prefix owl: . +@prefix xsd: . +@prefix dc: . +@prefix foaf: . +@prefix wv: . +@prefix sd: . +@prefix skos: . +@prefix skosmos: . +@prefix isothes: . +@prefix mdrtype: . +@prefix : <#> . + +# Skosmos main configuration + +:config a skosmos:Configuration ; + # SPARQL endpoint + # a local Fuseki server is usually on localhost:3030 + #skosmos:sparqlEndpoint ; + # use the dev.finto.fi endpoint where the example vocabularies reside + skosmos:sparqlEndpoint ; + # sparql-query extension, or "Generic" for plain SPARQL 1.1 + # set to "JenaText" instead if you use Fuseki with jena-text index + skosmos:sparqlDialect "Generic" ; + # whether to enable collation in sparql queries + skosmos:sparqlCollationEnabled false ; + # HTTP client configuration + skosmos:sparqlTimeout 20 ; + skosmos:httpTimeout 5 ; + # customize the service name + skosmos:serviceName "Skosmos" ; + # customize the base element. Set this if the automatic base url detection doesn't work. For example setups behind a proxy. + # skosmos:baseHref "http://localhost/Skosmos/" ; + # interface languages available, and the corresponding system locales + skosmos:languages ( + [ rdfs:label "fi" ; rdf:value "fi_FI.utf8" ] + [ rdfs:label "sv" ; rdf:value "sv_SE.utf8" ] + [ rdfs:label "en" ; rdf:value "en_GB.utf8" ] + ) ; + # how many results (maximum) to load at a time on the search results page + skosmos:searchResultsSize 20 ; + # how many items (maximum) to retrieve in transitive property queries + skosmos:transitiveLimit 1000 ; + # whether or not to log caught exceptions + skosmos:logCaughtExceptions false ; + # set to TRUE to enable logging into browser console + skosmos:logBrowserConsole false ; + # set to a logfile path to enable logging into log file + # skosmos:logFileName "" ; + # a default location for Twig template rendering + skosmos:templateCache "/tmp/skosmos-template-cache" ; + # customize the css by adding your own stylesheet + # skosmos:customCss "resource/css/stylesheet.css" ; + # default email address where to send the feedback + skosmos:feedbackAddress "" ; + # email address to set as the sender for feedback messages + skosmos:feedbackSender "" ; + # email address to set as the envelope sender for feedback messages + skosmos:feedbackEnvelopeSender "" ; + # whether to display the ui language selection as a dropdown (useful for cases where there are more than 3 languages) + skosmos:uiLanguageDropdown false ; + # whether to enable the spam honey pot or not, enabled by default + skosmos:uiHoneypotEnabled true ; + # default time a user must wait before submitting a form + skosmos:uiHoneypotTime 5 ; + # plugins to activate for the whole installation (including all vocabularies) + skosmos:globalPlugins () . + +# Skosmos vocabularies + +:ysa a skosmos:Vocabulary, void:Dataset ; + dc:title "YSA - Yleinen suomalainen asiasanasto"@fi, + "YSA - Allmän tesaurus på finska"@sv, + "YSA - General Finnish thesaurus"@en ; + dc:subject :cat_general ; + dc:type mdrtype:THESAURUS ; + void:uriSpace "http://www.yso.fi/onto/ysa/"; + skosmos:groupClass skos:Collection; + skosmos:language "fi"; + skosmos:shortName "YSA"; + skosmos:feedbackRecipient "vesa-posti@helsinki.fi" ; + skosmos:showChangeList "true" ; + void:dataDump ; + void:sparqlEndpoint ; + skosmos:sparqlGraph +. + +:yso a skosmos:Vocabulary, void:Dataset ; + dc:title "YSO - Yleinen suomalainen ontologia"@fi, + "ALLFO - Allmän finländsk ontologi"@sv, + "YSO - General Finnish ontology"@en ; + dc:subject :cat_general ; + dc:type mdrtype:ONTOLOGY ; + void:uriSpace "http://www.yso.fi/onto/yso/"; + skosmos:language "fi", "sv", "en"; + skosmos:defaultLanguage "fi"; + skosmos:showTopConcepts "true"; + skosmos:showStatistics "false"; + skosmos:loadExternalResources "false"; + skosmos:shortName "YSO", + "ALLFO"@sv; + skosmos:groupClass isothes:ConceptGroup ; + skosmos:arrayClass isothes:ThesaurusArray ; + void:dataDump ; + void:sparqlEndpoint ; + skosmos:sparqlGraph ; + skosmos:mainConceptScheme +. + +:categories a skos:ConceptScheme; + skos:prefLabel "Skosmos Vocabulary Categories"@en +. + +:cat_general a skos:Concept ; + skos:topConceptOf :categories ; + skos:inScheme :categories ; + skos:prefLabel "Yleiskäsitteet"@fi, + "Allmänna begrepp"@sv, + "General concepts"@en +. + +mdrtype:THESAURUS a skos:Concept ; + skos:prefLabel "Тезаурус"@bg, "Tezaurus"@cs, "Tesaurus"@da, "Thesaurus"@de, "Θησαυρός"@el, "Thesaurus"@en, "Tesaurus"@et, "Tesaurus"@fi, "Thésaurus"@fr, "Pojmovnik"@hr, "Tezaurusz"@hu, "Tesauro"@it, "Tēzaurs"@lv, "Tezauras"@lt, "Teżawru"@mt, "Thesaurus"@nl, "Tesaurus"@no, "Tezaurus"@pl, "Tesauro"@pt, "Tezaur"@ro, "Synonymický slovník"@sk, "Tezaver"@sl, "Tesauro"@es, "Tesaurus"@sv +. + +mdrtype:ONTOLOGY a skos:Concept ; + skos:prefLabel "Онтология"@bg, "Ontologie"@cs, "Ontologi"@da, "Ontologie"@de, "Οντολογία"@el, "Ontology"@en, "Ontoloogia"@et, "Ontologia"@fi, "Ontologie"@fr, "Ontologija"@hr, "Ontológia"@hu, "Ontologia"@it, "Ontoloģija"@lv, "Ontologija"@lt, "Ontoloġija"@mt, "Ontologie"@nl, "Ontologi"@no, "Struktura pojęciowa"@pl, "Ontologia"@pt, "Ontologie"@ro, "Ontológia"@sk, "Ontologija"@sl, "Ontología"@es, "Ontologi"@sv +. diff --git a/controller/Controller.php b/controller/Controller.php index d9058d6ec..ca50c0959 100644 --- a/controller/Controller.php +++ b/controller/Controller.php @@ -5,9 +5,15 @@ */ class Controller { + /** + * How long to store retrieved disk configuration for HTTP 304 header + * from git information. + */ + const GIT_MODIFIED_CONFIG_TTL = 600; // 10 minutes + /** * The controller has to know the model to access the data stored there. - * @param $model contains the Model object. + * @var Model $model contains the Model object. */ public $model; @@ -21,14 +27,15 @@ class Controller public function __construct($model) { $this->model = $model; - $this->negotiator = new \Negotiation\FormatNegotiator(); + $this->negotiator = new \Negotiation\Negotiator(); + $domain = 'skosmos'; // Specify the location of the translation tables - bindtextdomain('skosmos', 'resource/translations'); - bind_textdomain_codeset('skosmos', 'UTF-8'); + bindtextdomain($domain, 'resource/translations'); + bind_textdomain_codeset($domain, 'UTF-8'); // Choose domain for translations - textdomain('skosmos'); + textdomain($domain); // Build arrays of language information, with 'locale' and 'name' keys $this->languages = array(); @@ -48,6 +55,7 @@ public function setLanguageProperties($lang) { if (array_key_exists($lang, $this->languages)) { $locale = $this->languages[$lang]['locale']; + putenv("LANGUAGE=$locale"); putenv("LC_ALL=$locale"); setlocale(LC_ALL, $locale); } else { @@ -73,12 +81,20 @@ protected function negotiateFormat($choices, $accept, $format) } return $format; } - + // if there was no proposed format, negotiate a suitable format header('Vary: Accept'); // inform caches that a decision was made based on Accept header $best = $this->negotiator->getBest($accept, $choices); - $format = ($best !== null) ? $best->getValue() : null; - return $format; + return ($best !== null) ? $best->getValue() : null; + } + + private function isSecure() + { + if ($protocol = filter_input(INPUT_SERVER, 'HTTP_X_FORWARDED_PROTO', FILTER_SANITIZE_STRING)) { + return \in_array(strtolower($protocol), ['https', 'on', 'ssl', '1'], true); + } + + return filter_input(INPUT_SERVER, 'HTTPS', FILTER_SANITIZE_STRING) !== null; } private function guessBaseHref() @@ -92,12 +108,11 @@ private function guessBaseHref() $doc_root = preg_replace("!{$script_name}$!", '', $script_filename); $base_url = preg_replace("!^{$doc_root}!", '', $base_dir); $base_url = str_replace('/controller', '/', $base_url); - $protocol = filter_input(INPUT_SERVER, 'HTTPS', FILTER_SANITIZE_STRING) === null ? 'http' : 'https'; + $protocol = $this->isSecure() ? 'https' : 'http'; $port = filter_input(INPUT_SERVER, 'SERVER_PORT', FILTER_SANITIZE_STRING); - $disp_port = ($protocol == 'http' && $port == 80 || $protocol == 'https' && $port == 443) ? '' : ":$port"; + $disp_port = ($port == 80 || $port == 443) ? '' : ":$port"; $domain = filter_input(INPUT_SERVER, 'SERVER_NAME', FILTER_SANITIZE_STRING); - $full_url = "$protocol://{$domain}{$disp_port}{$base_url}"; - return $full_url; + return "$protocol://{$domain}{$disp_port}{$base_url}"; } public function getBaseHref() @@ -105,6 +120,56 @@ public function getBaseHref() return ($this->model->getConfig()->getBaseHref() !== null) ? $this->model->getConfig()->getBaseHref() : $this->guessBaseHref(); } + /** + * Creates Skosmos links from uris. + * @param string $uri + * @param Vocabulary $vocab + * @param string $lang + * @param string $type + * @param string $clang content + * @param string $term + * @throws Exception if the vocabulary ID is not found in configuration + * @return string containing the Skosmos link + */ + public function linkUrlFilter($uri, $vocab, $lang, $type = 'page', $clang = null, $term = null) { + // $vocab can either be null, a vocabulary id (string) or a Vocabulary object + if ($vocab === null) { + // target vocabulary is unknown, best bet is to link to the plain URI + return $uri; + } elseif (is_string($vocab)) { + $vocid = $vocab; + $vocab = $this->model->getVocabulary($vocid); + } else { + $vocid = $vocab->getId(); + } + + $params = array(); + if (isset($clang) && $clang !== $lang) { + $params['clang'] = $clang; + } + + if (isset($term)) { + $params['q'] = $term; + } + + // case 1: URI within vocabulary namespace: use only local name + $localname = $vocab->getLocalName($uri); + if ($localname !== $uri && $localname === urlencode($localname)) { + // check that the prefix stripping worked, and there are no problematic chars in localname + $paramstr = count($params) > 0 ? '?' . http_build_query($params) : ''; + if ($type && $type !== '' && $type !== 'vocab' && !($localname === '' && $type === 'page')) { + return "$vocid/$lang/$type/$localname" . $paramstr; + } + + return "$vocid/$lang/$localname" . $paramstr; + } + + // case 2: URI outside vocabulary namespace, or has problematic chars + // pass the full URI as parameter instead + $params['uri'] = $uri; + return "$vocid/$lang/$type/?" . http_build_query($params); + } + /** * Echos an error message when the request can't be fulfilled. * @param string $code @@ -117,4 +182,148 @@ protected function returnError($code, $status, $message) header("Content-type: text/plain; charset=utf-8"); echo "$code $status : $message"; } + + protected function notModified(Modifiable $modifiable = null) + { + $notModified = false; + if ($modifiable !== null && $modifiable->isUseModifiedDate()) { + $modifiedDate = $this->getModifiedDate($modifiable); + $notModified = $this->sendNotModifiedHeader($modifiedDate); + } + return $notModified; + } + + /** + * Return the modified date. + * + * @param Modifiable $modifiable + * @return DateTime|null + */ + protected function getModifiedDate(Modifiable $modifiable = null) + { + $modified = null; + $modifiedDate = $modifiable !== null ? $modifiable->getModifiedDate() : null; + $gitModifiedDate = $this->getGitModifiedDate(); + $configModifiedDate = $this->getConfigModifiedDate(); + + // max with an empty list raises an error and returns bool + if ($modifiedDate || $gitModifiedDate || $configModifiedDate) { + $modified = max($modifiedDate, $gitModifiedDate, $configModifiedDate); + } + return $modified; + } + + /** + * Return the datetime of the latest commit, or null if git is not available or if the command failed + * to execute. + * + * @see https://stackoverflow.com/a/33986403 + * @return DateTime|null + */ + protected function getGitModifiedDate() + { + $commitDate = null; + $cache = $this->model->getConfig()->getCache(); + $cacheKey = "git:modified_date"; + $gitCommand = 'git log -1 --date=iso --pretty=format:%cd'; + if ($cache->isAvailable()) { + $commitDate = $cache->fetch($cacheKey); + if (!$commitDate) { + $commitDate = $this->executeGitModifiedDateCommand($gitCommand); + if ($commitDate) { + $cache->store($cacheKey, $commitDate, static::GIT_MODIFIED_CONFIG_TTL); + } + } + } else { + $commitDate = $this->executeGitModifiedDateCommand($gitCommand); + } + return $commitDate; + } + + /** + * Execute the git command and return a parsed date time, or null if the command failed. + * + * @param string $gitCommand git command line that returns a formatted date time + * @return DateTime|null + */ + protected function executeGitModifiedDateCommand($gitCommand) + { + $commitDate = null; + $commandOutput = @exec($gitCommand); + if ($commandOutput) { + $commitDate = new \DateTime(trim($commandOutput)); + $commitDate->setTimezone(new \DateTimeZone('UTC')); + } + return $commitDate; + } + + /** + * Return the datetime of the modified time of the config file. This value is read in the GlobalConfig + * for every request, so we simply access that value and if not null, we will return a datetime. Otherwise, + * we return a null value. + * + * @see http://php.net/manual/en/function.filemtime.php + * @return DateTime|null + */ + protected function getConfigModifiedDate() + { + $dateTime = null; + $configModifiedTime = $this->model->getConfig()->getConfigModifiedTime(); + if ($configModifiedTime !== null) { + $dateTime = (new DateTime())->setTimestamp($configModifiedTime); + } + return $dateTime; + } + + /** + * If the $modifiedDate is a valid DateTime, and if the $_SERVER variable contains the right info, and + * if the $modifiedDate is not more recent than the latest value in $_SERVER, then this function sets the + * HTTP 304 not modified and returns true.. + * + * If the $modifiedDate is still valid, then it sets the Last-Modified header, to be used by the browser for + * subsequent requests, and returns false. + * + * Otherwise, it returns false. + * + * @param DateTime|null $modifiedDate the last modified date to be compared against server's modified since information + * @return bool whether it sent the HTTP 304 not modified headers or not (useful for sending the response without + * further actions) + */ + protected function sendNotModifiedHeader($modifiedDate): bool + { + if ($modifiedDate) { + $ifModifiedSince = $this->getIfModifiedSince(); + $this->sendHeader("Last-Modified: " . $modifiedDate->format('D, d M Y H:i:s \G\M\T')); + if ($ifModifiedSince !== null && $ifModifiedSince >= $modifiedDate) { + $this->sendHeader("HTTP/1.0 304 Not Modified"); + return true; + } + } + return false; + } + + /** + * @return DateTime|null a DateTime object if the value exists in the $_SERVER variable, null otherwise + */ + protected function getIfModifiedSince() + { + $ifModifiedSince = null; + $ifModSinceHeader = filter_input(INPUT_SERVER, 'HTTP_IF_MODIFIED_SINCE', FILTER_SANITIZE_STRING); + if ($ifModSinceHeader) { + // example value set by a browser: "Mon, 11 May 2020 10:46:57 GMT" + $ifModifiedSince = new DateTime($ifModSinceHeader); + } + return $ifModifiedSince; + } + + /** + * Sends HTTP headers. Simply calls PHP built-in header function. But being + * a function here, it can easily be tested/mocked. + * + * @param $header string header to be sent + */ + protected function sendHeader($header) + { + header($header); + } } diff --git a/controller/EntityController.php b/controller/EntityController.php index afba507f8..ffdfdeb4e 100644 --- a/controller/EntityController.php +++ b/controller/EntityController.php @@ -19,19 +19,25 @@ private function redirectREST($vocab, $uri, $targetFormat) $url = $baseurl . "rest/v1/$vocid/data?$query"; $this->redirect303($url); } - + private function redirectWeb($vocab, $uri) { $baseurl = $this->getBaseHref(); $vocid = $vocab->getId(); $localname = $vocab->getLocalName($uri); - if ($localname !== $uri && $localname === urlencode($localname)) { - // the URI can be shortened - $url = $baseurl . "$vocid/page/$localname"; + + if (!$localname) { + $url = $baseurl . "$vocid/"; } else { - // must use full URI - $query = http_build_query(array('uri'=>$uri)); - $url = $baseurl . "$vocid/page/?" . $query; + + if ($localname !== $uri && $localname === urlencode($localname)) { + // the URI can be shortened + $url = $baseurl . "$vocid/page/$localname"; + } else { + // must use full URI + $query = http_build_query(array('uri'=>$uri)); + $url = $baseurl . "$vocid/page/?" . $query; + } } $this->redirect303($url); } @@ -65,7 +71,7 @@ public function redirect($request) { $requestedFormat = $request->getQueryParam('format'); $targetFormat = $this->negotiateFormat($supportedFormats, $request->getServerConstant('HTTP_ACCEPT'), $requestedFormat); - + if (in_array($targetFormat, $restFormats)) { $this->redirectREST($request->getVocab(), $request->getUri(), $targetFormat); } else { diff --git a/controller/Honeypot.php b/controller/Honeypot.php index 052363fe6..917fc9a95 100644 --- a/controller/Honeypot.php +++ b/controller/Honeypot.php @@ -32,11 +32,10 @@ public function generate($honey_name, $honey_time) { // Encrypt the current time $honey_time_encrypted = $this->getEncryptedTime(); - $html = ' -
-

{% if ServiceName != 'SERVICE_NAME' %}{{ ServiceName }}{% else %}Skosmos{% endif %} {% trans "layout designed by Hahmo" %}

-
-
-

{% trans %}Skosmos version {{ version }}{% endtrans %}

+
+
+

{% if ServiceName != 'SERVICE_NAME' %}{{ ServiceName }}{% else %}Skosmos{% endif %} {% trans "layout designed by Hahmo" %}

+
+
+

{% trans %}Skosmos version {{ version }}{% endtrans %}

+
{% endblock %} diff --git a/view/changes.twig b/view/changes.twig index 1d252490f..1a9cbf18d 100644 --- a/view/changes.twig +++ b/view/changes.twig @@ -3,24 +3,30 @@ {% block sidebar %} +

{% trans "Listing vocabulary concepts by newest additions" %}