diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 index 940fe28..7604569 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,285 @@ -# generic -.DS_Store -.vagrant -*.pyc +# Created by https://www.toptal.com/developers/gitignore/api/python,visualstudiocode,pycharm+iml +# Edit at https://www.toptal.com/developers/gitignore?templates=python,visualstudiocode,pycharm+iml -# code & config -_service-provider/* -_solr/schema.xml -_src/* -local/* -.vscode/settings.json +### PyCharm+iml ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm+iml Patch ### +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/python,visualstudiocode,pycharm+iml + +.git-old/* +.github \ No newline at end of file diff --git a/.hadolint.yaml b/.hadolint.yaml new file mode 100644 index 0000000..502b578 --- /dev/null +++ b/.hadolint.yaml @@ -0,0 +1,3 @@ +ignored: + - DL3018 + - DL3008 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..40d17f8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "files.associations": { + "*html": "jinja-html" + }, + "emmet.includeLanguages": { + "jinja-html": "*html" + } +} \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..04b029f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at info@keitaro.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7edd28e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,27 @@ +## How to contribute to Dockerized CKAN + +#### **Did you find a bug?** + +* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/keitaroinc/docker-ckan/issues). + +* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/keitaroinc/docker-ckan/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, we include an issue template to help out in filling-in the issue. + +#### **Did you write a patch that fixes a bug?** + +* Open a new GitHub pull request with the patch. + +* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. + +#### **Do you intend to add a new feature or change an existing one?** + +* [Create a new feature issue](https://github.com/keitaroinc/docker-ckan/issues/new) using the Feature Request template and describe your proposed changes + +* Submit a pull request referring to the relevant feature issue/s + +#### **Do you have questions about the source code?** + +* Ask any question about how to use Dockerized CKAN in our [gitter chat](https://gitter.im/keitaroinc/docker-ckan). + +Thanks! + +Keitaro Team diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..725a7a7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2020 Keitaro AB + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..903797e --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +VERSION := $(shell git describe --tags --exact-match 2>/dev/null || echo latest) +DOCKERHUB_NAMESPACE ?= keitaro +IMAGE := ${DOCKERHUB_NAMESPACE}/ckan:${VERSION} + +build: + docker build -t ${IMAGE} rootfs + +push: build + docker push ${IMAGE} diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..2ee6539 --- /dev/null +++ b/NOTICE @@ -0,0 +1,2 @@ +docker-ckan +Copyright (c) 2016 Keitaro AB diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..d50994f --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,6 @@ +# Roadmap + +- [ ] Fix Filters in search pages +- [ ] fix tags page(home sees tags, but "all tags" does not) +- [ ] check if all requested plugins are working +- [ ] \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..511c630 --- /dev/null +++ b/Readme.md @@ -0,0 +1,115 @@ +# Dockerized CKAN + +[![build-status](https://github.com/keitaroinc/docker-ckan/workflows/Docker%20Image%20Build/badge.svg?branch=master)](https://github.com/keitaroinc/docker-ckan/actions) [![License][]][1] [![Docker Pulls][]][2] [![Chat on Gitter][]][3] + +This repository contains base docker images, examples and docker-compose used to build and run CKAN. + +We build and publish docker images built using this repository to Dockerhub: +- [CKAN docker images](https://hub.docker.com/r/keitaro/ckan). +- [Datapusher docker images](https://hub.docker.com/r/keitaro/ckan-datapusher) + +and Github Container Registry: +- [CKAN docker images on GHCR](https://github.com/orgs/keitaroinc/packages/container/package/ckan) +- [Datapusher docker images on GHCR](https://github.com/orgs/keitaroinc/packages/container/package/datapusher) + +Looking to run CKAN on Kubernetes? Check out our [CKAN Helm Chart](https://github.com/keitaroinc/ckan-helm)! + +## Overview +Images are provided in two flavors: +- [Alpine Linux](https://alpinelinux.org/) based images +- [Ubuntu Focal](https://ubuntu.com/) based images are the ones ending with `-focal` in the tag name + +The Docker containers include only the required extensions to start a CKAN instance. The docker images are built using a multi-stage docker approach in order to produce slim production grade docker images with the right libraries and configuration. This multi-stage approach allows us to build python binary wheels in the build stages that later on we install in the main stage. + +Directory layout: +- [compose](./compose) - contains a docker-compose setup allowing users to spin up a CKAN setup easily using [docker-compose](https://docs.docker.com/compose/) +- [images](./images) - includes docker contexts for building all supported CKAN versions and datapusher +- [examples](./examples) - includes examples on how to extend the CKAN docker images and how to run them + +## Running CKAN using docker-compose +To start CKAN using docker-compose, simply change into the *compose* directory and run +```sh +cd compose/2.9 +docker-compose build +docker-compose up +``` +Check if CKAN was succesfuly started on http://localhost:5000. + +### Configuration +In order to configure CKAN within docker-compose we use both build/up time variables loaded via the [.env](./compose/2.9/.env) file, and runtime variables loaded via the [.ckan-env](./compose/2.9/.ckan-env) file. + +Variables in the [.env](./compose/2.9/.env) file are loaded when running `docker-compose build` and `docker-compose up`, while variables in [.ckan-env](./compose/2.9/.ckan-env) file are used withing the CKAN container at runtime to configure CKAN and CKAN extensions using [ckanext-envvars](https://github.com/okfn/ckanext-envvars). + +## Extending CKAN docker images +Check some examples of extending CKAN docker images in the [examples](./examples) directory. + +We recommend to use a multi-stage approach to extend the docker images that we provide here. To extend the images the following Dockerfile structure is recommended: +```docker +################### +### Extensions #### +################### +FROM ghcr.io/keitaroinc/ckan:2.9.9 as extbuild + +# Switch to the root user +USER root + +# Install any system packages necessary to build extensions +# Make sure we install python 3.8, cause CKAN is not compatible with 3.9 +RUN apk add --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/v3.13/main \ + python3-dev=3.8.10-r0 + +# Fetch and build the custom CKAN extensions +RUN pip wheel --wheel-dir=/wheels git+https://github.com/acmecorp/ckanext-acme@0.0.1#egg=ckanext-acme + +############ +### MAIN ### +############ +FROM ghcr.io/keitaroinc/ckan:2.9.9 + +# Add the custom extensions to the plugins list +ENV CKAN__PLUGINS envvars image_view text_view recline_view datastore datapusher acme + +# Switch to the root user +USER root + +COPY --from=extbuild /wheels /srv/app/ext_wheels + +# Install and enable the custom extensions +RUN pip install --no-index --find-links=/srv/app/ext_wheels ckanext-acme && \ + ckan config-tool ${APP_DIR}/production.ini "ckan.plugins = ${CKAN__PLUGINS}" && \ + chown -R ckan:ckan /srv/app + +# Remove wheels +RUN rm -rf /srv/app/ext_wheels + +# Switch to the ckan user +USER ckan +``` + +### Adding init and afterinit scripts +You can add scripts to CKAN custom images and copy them to the *docker-entrypoint.d* directory. Any *.sh or *.py file in that directory will be executed before the main initialization script (prerun.py) is executed. + +You can add scripts to CKAN custom images and copy them to the *docker-afterinit.d* directory. Any *.sh or *.py file in that directory will be executed after the main initialization script (prerun.py) is executed. + +## Build +To build a CKAN image run: +```sh +docker build --tag ghcr.io/keitaroinc/ckan:2.9.9 images/ckan/2.9 +``` +The –-tag ghcr.io/keitaroinc/ckan:2.9.9 flag sets the image name to ghcr.io/keitaroinc/ckan:2.9.9 and 'images/ckan/2.9' at the end tells docker build to use the context into the specified directory where the Dockerfile and related contents are. + +## Upload to DockerHub +>*It's recommended to upload built images to DockerHub* + +To upload the image to DockerHub run: + +```sh +docker push [options] /ckan: +``` + + [License]: https://img.shields.io/badge/license-Apache--2.0-blue.svg?style=flat + [1]: https://opensource.org/licenses/Apache-2.0 + [Docker Pulls]: https://img.shields.io/docker/pulls/keitaro/ckan.svg?style=flat + [2]: https://hub.docker.com/r/keitaro/ckan + [Chat on Gitter]: https://badges.gitter.im/gitterHQ/gitter.svg + [3]: https://gitter.im/keitaroinc/docker-ckan diff --git a/compose/2.10/.ckan.env b/compose/2.10/.ckan.env new file mode 100644 index 0000000..ca6058a --- /dev/null +++ b/compose/2.10/.ckan.env @@ -0,0 +1,44 @@ +# Runtime configuration of CKAN enabled through ckanext-envvars +# Information about how it works: https://github.com/okfn/ckanext-envvars +# Note that variables here take presedence over build/up time variables in .env + +DEVELOPMENT=true + +# Set to true to disable CKAN from starting and serve a maintenance page +MAINTENANCE_MODE=false + +# General Settings +CKAN_SITE_ID=default +CKAN_SITE_URL=http://localhost:5000 +CKAN_PORT=5000 +CKAN_MAX_UPLOAD_SIZE_MB=200 +CKAN___BEAKER__SESSION__SECRET=CHANGE_ME +# See https://docs.ckan.org/en/latest/maintaining/configuration.html#api-token-settings +CKAN___API_TOKEN__JWT__ENCODE__SECRET=string:CHANGE_ME +CKAN___API_TOKEN__JWT__DECODE__SECRET=string:CHANGE_ME +# CKAN Plugins +CKAN__PLUGINS="envvars image_view text_view recline_view datastore datapusher spatial_metadata spatial_query d4science d4science_theme" +# CKAN requires storage path to be set in order for filestore to be enabled +CKAN__STORAGE_PATH=/srv/app/data +CKAN__WEBASSETS__PATH=/srv/app/data/webassets +# SYSADMIN settings, a sysadmin user is created automatically with the below credentials +CKAN_SYSADMIN_NAME=sysadmin +CKAN_SYSADMIN_PASSWORD=password +CKAN_SYSADMIN_EMAIL=sysadmin@ckantest.com + +# Email settings +CKAN_SMTP_SERVER=smtp.corporateict.domain:25 +CKAN_SMTP_STARTTLS=True +CKAN_SMTP_USER=user +CKAN_SMTP_PASSWORD=pass +CKAN_SMTP_MAIL_FROM=ckan@localhost + +# Datapusher configuration +CKAN__DATAPUSHER__URL=http://datapusher:8000 +CKAN__DATAPUSHER__CALLBACK_URL_BASE=http://ckan:5000/ +CKAN__DATAPUSHER__API_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ6M0lGRGw4SVdFR3lVRzFYRHJ0cm56WmNmcDlzbmFuUHlUMjdqLXRVSW9nIiwiaWF0IjoxNjc3MDYwNjQ1fQ.ECCa0wU-FOOGpdE9_TTVj__2J9SfANRBD6gRClBvPk0 +# CKAN__DATAPUSHER__API_TOKEN=replace_this_with_api_token_once_ckan_starts + +# Solr configuration +CKAN_VERSION=2.10 +CKAN_CORE_NAME=ckan diff --git a/compose/2.10/Dockerfile b/compose/2.10/Dockerfile new file mode 100644 index 0000000..e5411d9 --- /dev/null +++ b/compose/2.10/Dockerfile @@ -0,0 +1,39 @@ +################### +### Extensions +################### +FROM registry.trust-itservices.com/d4science/ckan-docker/ckan:2.10.4-focal as extbuild + +# Switch to the root user +USER root + +#install pip +RUN apt-get update +RUN apt-get install python3-dev python3-pip libxml2-dev libxslt1-dev libgeos-c1v5 -y + +############ +### MAIN +############ +FROM registry.trust-itservices.com/d4science/ckan-docker/ckan:2.10.4-focal + +# Add the custom extensions to the plugins list +ENV CKAN__PLUGINS envvars image_view text_view recline_view datastore datapusher spatial_metadata spatial_query d4science d4science_theme + +# Switch to the root user +USER root + +#COPY --from=extbuild /wheels /srv/app/ext_wheels + +# Add requirements.txt to the image +COPY requirements.txt /srv/app/requirements.txt + +# Install and enable the custom extensions +RUN pip install -r /srv/app/requirements.txt + +RUN ckan config-tool ${APP_DIR}/production.ini "ckan.plugins = ${CKAN__PLUGINS}" && \ + chown -R ckan:ckan /srv/app + +# Remove wheels +RUN rm -rf /srv/app/ext_wheels + +# Switch to the ckan user +# USER ckan diff --git a/compose/2.10/ckan-docker.code-workspace b/compose/2.10/ckan-docker.code-workspace new file mode 100644 index 0000000..407c760 --- /dev/null +++ b/compose/2.10/ckan-docker.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "../.." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/compose/2.10/docker-compose.yml b/compose/2.10/docker-compose.yml new file mode 100644 index 0000000..8288623 --- /dev/null +++ b/compose/2.10/docker-compose.yml @@ -0,0 +1,99 @@ +# docker-compose build && docker-compose up -d +version: "3.8" + +volumes: + ckan_data: + pg_data: + solr_data: + +services: + ckan: + container_name: ckan + build: + context: . + networks: + - frontend + - backend + depends_on: + - db + - solr + ports: + - "0.0.0.0:${CKAN_PORT}:5000" + env_file: + - ./.ckan.env + environment: + - CKAN_SQLALCHEMY_URL=postgresql://ckan:${POSTGRES_PASSWORD}@db/ckan + - CKAN_DATASTORE_WRITE_URL=postgresql://ckan:${POSTGRES_PASSWORD}@db/datastore + - CKAN_DATASTORE_READ_URL=postgresql://datastore_ro:${DATASTORE_READONLY_PASSWORD}@db/datastore + - CKAN_SOLR_URL=http://solr:8983/solr/ckan + - CKAN_REDIS_URL=redis://redis:6379/1 + - CKAN_SITE_URL=${CKAN_SITE_URL} + - CKAN_MAX_UPLOAD_SIZE_MB=${CKAN_MAX_UPLOAD_SIZE_MB} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - DS_RO_PASS=${DATASTORE_READONLY_PASSWORD} + + volumes: + - ckan_data:/srv/app/data + - ./src:/srv/app/src_extensions + - ./docker-entrypoint.d:/srv/app/docker-entrypoint.d + + datapusher: + container_name: datapusher + image: ghcr.io/keitaroinc/datapusher:${DATAPUSHER_VERSION} + networks: + - frontend + - backend + ports: + - "8000:8000" + environment: + - DATAPUSHER_MAX_CONTENT_LENGTH=${DATAPUSHER_MAX_CONTENT_LENGTH} + - DATAPUSHER_CHUNK_SIZE=${DATAPUSHER_CHUNK_SIZE} + - DATAPUSHER_CHUNK_INSERT_ROWS=${DATAPUSHER_CHUNK_INSERT_ROWS} + - DATAPUSHER_DOWNLOAD_TIMEOUT=${DATAPUSHER_DOWNLOAD_TIMEOUT} + - DATAPUSHER_SSL_VERIFY=${DATA_PUSHER_SSL_VERIFY} + - DATAPUSHER_REWRITE_RESOURCES=${DATAPUSHER_REWRITE_RESOURCES} + - DATAPUSHER_REWRITE_URL=${DATAPUSHER_REWRITE_URL} + + + db: + container_name: db + build: + context: . + dockerfile: postgresql/Dockerfile + args: + - DS_RO_PASS=${DATASTORE_READONLY_PASSWORD} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + networks: + - backend + environment: + - DS_RO_PASS=${DATASTORE_READONLY_PASSWORD} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - PGDATA=/var/lib/postgresql/data/db + volumes: + - pg_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-U", "ckan"] + + solr: + container_name: solr + image: ckan/ckan-solr:2.10-solr9-spatial + networks: + - backend + env_file: + - ./.ckan.env + environment: + - CKAN_CORE_NAME=${CKAN_CORE_NAME} + - CKAN_VERSION=${CKAN_VERSION} + volumes: + - solr_data:/var/solr + - ${PWD}/solr8/ckan_init_solr.sh:/docker-entrypoint-initdb.d/ckan_init_solr.sh + + redis: + container_name: redis + image: redis:${REDIS_VERSION} + networks: + - backend + +networks: + frontend: + backend: diff --git a/compose/2.10/docker-entrypoint.d/00_set_ckan_devserver.sh b/compose/2.10/docker-entrypoint.d/00_set_ckan_devserver.sh new file mode 100644 index 0000000..6b0c2f3 --- /dev/null +++ b/compose/2.10/docker-entrypoint.d/00_set_ckan_devserver.sh @@ -0,0 +1 @@ +ckan config-tool ${APP_DIR}/production.ini "ckan.devserver.watch_patterns = **/*.py **/*.html" \ No newline at end of file diff --git a/compose/2.10/docker-entrypoint.d/01_setup_spatial.sh b/compose/2.10/docker-entrypoint.d/01_setup_spatial.sh new file mode 100644 index 0000000..8d387a3 --- /dev/null +++ b/compose/2.10/docker-entrypoint.d/01_setup_spatial.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +if [[ $CKAN__PLUGINS == *"spatial_metadata"* ]]; then + echo "Configuring CKAN spatial ..." + + ckan config-tool ${APP_DIR}/production.ini "ckanext.spatial.common_map.type=Stadia.StamenTerrain" + ckan config-tool ${APP_DIR}/production.ini "ckanext.spatial.common_map.max_zoom=18" + # ckan config-tool $CKAN_INI "ckanext.spatial.search_backend = solr-spatial-field" + ckan config-tool ${APP_DIR}/production.ini "ckan.search.solr_allowed_query_parsers = frange" + # forse è da aggiungere un qualche tipo di key per production + +else + echo "Not configuring spatial, plugin not enabled." +fi diff --git a/compose/2.10/docker-entrypoint.d/02_setup_extensions.sh b/compose/2.10/docker-entrypoint.d/02_setup_extensions.sh new file mode 100644 index 0000000..7f6f9c8 --- /dev/null +++ b/compose/2.10/docker-entrypoint.d/02_setup_extensions.sh @@ -0,0 +1,42 @@ +SRC_EXTENSIONS_DIR=/srv/app/src_extensions + +# Install any local extensions in the src_extensions volume +echo "Looking for local extensions to install..." +echo "Extension dir ($SRC_EXTENSIONS_DIR) contents:" +ls -la $SRC_EXTENSIONS_DIR +for i in $SRC_EXTENSIONS_DIR/* +do + if [ -d $i ]; + then + + if [ -f $i/pip-requirements.txt ]; + then + pip install -r $i/pip-requirements.txt + echo "Found requirements file in $i" + fi + if [ -f $i/requirements.txt ]; + then + pip install -r $i/requirements.txt + echo "Found requirements file in $i" + fi + if [ -f $i/dev-requirements.txt ]; + then + pip install -r $i/dev-requirements.txt + echo "Found dev-requirements file in $i" + fi + if [ -f $i/setup.py ]; + then + cd $i + python3 $i/setup.py develop + echo "Found setup.py file in $i" + cd $APP_DIR + fi + + # Point `use` in test.ini to location of `test-core.ini` + if [ -f $i/test.ini ]; + then + echo "Updating \`test.ini\` reference to \`test-core.ini\` for plugin $i" + ckan config-tool $i/test.ini "use = config:../../src/ckan/test-core.ini" + fi + fi +done diff --git a/compose/2.10/postgresql/Dockerfile b/compose/2.10/postgresql/Dockerfile new file mode 100644 index 0000000..e5fcbb7 --- /dev/null +++ b/compose/2.10/postgresql/Dockerfile @@ -0,0 +1,13 @@ +FROM postgis/postgis:14-3.2-alpine + +# Allow connections; we don't map out any ports so only linked docker containers can connect +RUN echo "host all all 0.0.0.0/0 md5" >> /var/lib/postgresql/data/pg_hba.conf + +# Customize default user/pass/db +ENV POSTGRES_DB ckan +ENV POSTGRES_USER ckan +ARG POSTGRES_PASSWORD +ARG DS_RO_PASS + +# Include datastore setup scripts +COPY ./postgresql/docker-entrypoint-initdb.d /docker-entrypoint-initdb.d diff --git a/compose/2.10/postgresql/docker-entrypoint-initdb.d/00_create_datastore.sh b/compose/2.10/postgresql/docker-entrypoint-initdb.d/00_create_datastore.sh new file mode 100644 index 0000000..ec1b3c3 --- /dev/null +++ b/compose/2.10/postgresql/docker-entrypoint-initdb.d/00_create_datastore.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL + CREATE ROLE datastore_ro NOSUPERUSER NOCREATEDB NOCREATEROLE LOGIN PASSWORD '$DS_RO_PASS'; + CREATE DATABASE datastore OWNER ckan ENCODING 'utf-8'; + GRANT ALL PRIVILEGES ON DATABASE datastore TO ckan; +EOSQL \ No newline at end of file diff --git a/compose/2.10/postgresql/docker-entrypoint-initdb.d/20_postgis_permissions.sql b/compose/2.10/postgresql/docker-entrypoint-initdb.d/20_postgis_permissions.sql new file mode 100644 index 0000000..8b5348e --- /dev/null +++ b/compose/2.10/postgresql/docker-entrypoint-initdb.d/20_postgis_permissions.sql @@ -0,0 +1,2 @@ +ALTER VIEW geometry_columns OWNER TO ckan; +ALTER TABLE spatial_ref_sys OWNER TO ckan; diff --git a/compose/2.10/requirements.txt b/compose/2.10/requirements.txt new file mode 100644 index 0000000..9db4c49 --- /dev/null +++ b/compose/2.10/requirements.txt @@ -0,0 +1,3 @@ +# Spatial +-e git+https://github.com/ckan/ckanext-spatial.git@v2.1.1#egg=ckanext-spatial +-r https://raw.githubusercontent.com/ckan/ckanext-spatial/v2.1.1/requirements.txt diff --git a/compose/2.10/solr8/ckan_init_solr.sh b/compose/2.10/solr8/ckan_init_solr.sh new file mode 100755 index 0000000..091450f --- /dev/null +++ b/compose/2.10/solr8/ckan_init_solr.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Initialize SOLR for CKAN by creating a ckan core +# Arguments are supplied via environment variables: CKAN_CORE_NAME CKAN_VERSION +# Example: +# CKAN_CORE_NAME=ckan +# CKAN_VERSION=2.9.7 + +set -e + +MAJOR_VERSION=`echo $CKAN_VERSION | cut -d "." -f 1` +MINOR_VERSION=`echo $CKAN_VERSION | cut -d "." -f 2` + +CKAN_SOLR_SCHEMA_URL=https://raw.githubusercontent.com/ckan/ckan/`echo $MAJOR_VERSION.$MINOR_VERSION`/ckan/config/solr/schema.xml + +echo "Check whether managed schema exists for CKAN $CKAN_VERSION" +if ! curl --output /dev/null --silent --head --fail "$CKAN_SOLR_SCHEMA_URL"; then + echo "Can't find CKAN SOLR schema at URL: $CKAN_SOLR_SCHEMA_URL. Exiting..." + exit 1 +fi + +echo "Check whether SOLR is initialized for CKAN" +CORESDIR=/var/solr/data + +COREDIR="$CORESDIR/$CKAN_CORE_NAME" +if [ -d "$COREDIR" ]; then + echo "SOLR already initialized, skipping initialization" +else + echo "Initializing SOLR core $CKAN_CORE_NAME for CKAN $CKAN_VERSION" + # init script for handling an empty /var/solr + /opt/docker-solr/scripts/init-var-solr + + # Precreate CKAN core + /opt/docker-solr/scripts/precreate-core $CKAN_CORE_NAME + + # Replace the managed schema with CKANs schema + echo "Adding CKAN managed schema" + curl $CKAN_SOLR_SCHEMA_URL -o /var/solr/data/$CKAN_CORE_NAME/conf/managed-schema -s + + echo "SOLR initialized" +fi diff --git a/compose/2.10/src/ckanext-d4science/.coveragerc b/compose/2.10/src/ckanext-d4science/.coveragerc new file mode 100644 index 0000000..895e291 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/.coveragerc @@ -0,0 +1,5 @@ +[report] +omit = + */site-packages/* + */python?.?/* + ckan/* diff --git a/compose/2.10/src/ckanext-d4science/.gitignore b/compose/2.10/src/ckanext-d4science/.gitignore new file mode 100644 index 0000000..8570dc5 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/.gitignore @@ -0,0 +1,42 @@ +.ropeproject +node_modules +bower_components + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +sdist/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Sphinx documentation +docs/_build/ diff --git a/compose/2.10/src/ckanext-d4science/LICENSE b/compose/2.10/src/ckanext-d4science/LICENSE new file mode 100644 index 0000000..58777e3 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/LICENSE @@ -0,0 +1,661 @@ +GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/compose/2.10/src/ckanext-d4science/MANIFEST.in b/compose/2.10/src/ckanext-d4science/MANIFEST.in new file mode 100644 index 0000000..3d68def --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/MANIFEST.in @@ -0,0 +1,5 @@ +include README.rst +include LICENSE +include requirements.txt +recursive-include ckanext/d4science *.html *.json *.js *.less *.css *.mo *.yml +recursive-include ckanext/d4science/migration *.ini *.py *.mako diff --git a/compose/2.10/src/ckanext-d4science/README.md b/compose/2.10/src/ckanext-d4science/README.md new file mode 100644 index 0000000..17f8649 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/README.md @@ -0,0 +1,123 @@ +[![Tests](https://github.com/d4science/ckanext-d4science/workflows/Tests/badge.svg?branch=main)](https://github.com/d4science/ckanext-d4science/actions) + +# ckanext-d4science + +**TODO:** Put a description of your extension here: What does it do? What features does it have? Consider including some screenshots or embedding a video! + + +## Requirements + +**TODO:** For example, you might want to mention here which versions of CKAN this +extension works with. + +If your extension works across different versions you can add the following table: + +Compatibility with core CKAN versions: + +| CKAN version | Compatible? | +| --------------- | ------------- | +| 2.6 and earlier | not tested | +| 2.7 | not tested | +| 2.8 | not tested | +| 2.9 | not tested | + +Suggested values: + +* "yes" +* "not tested" - I can't think of a reason why it wouldn't work +* "not yet" - there is an intention to get it working +* "no" + + +## Installation + +**TODO:** Add any additional install steps to the list below. + For example installing any non-Python dependencies or adding any required + config settings. + +To install ckanext-d4science: + +1. Activate your CKAN virtual environment, for example: + + . /usr/lib/ckan/default/bin/activate + +2. Clone the source and install it on the virtualenv + + git clone https://github.com/d4science/ckanext-d4science.git + cd ckanext-d4science + pip install -e . + pip install -r requirements.txt + +3. Add `d4science` to the `ckan.plugins` setting in your CKAN + config file (by default the config file is located at + `/etc/ckan/default/ckan.ini`). + +4. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu: + + sudo service apache2 reload + + +## Config settings + +None at present + +**TODO:** Document any optional config settings here. For example: + + # The minimum number of hours to wait before re-checking a resource + # (optional, default: 24). + ckanext.d4science.some_setting = some_default_value + + +## Developer installation + +To install ckanext-d4science for development, activate your CKAN virtualenv and +do: + + git clone https://github.com/d4science/ckanext-d4science.git + cd ckanext-d4science + python setup.py develop + pip install -r dev-requirements.txt + + +## Tests + +To run the tests, do: + + pytest --ckan-ini=test.ini + + +## Releasing a new version of ckanext-d4science + +If ckanext-d4science should be available on PyPI you can follow these steps to publish a new version: + +1. Update the version number in the `setup.py` file. See [PEP 440](http://legacy.python.org/dev/peps/pep-0440/#public-version-identifiers) for how to choose version numbers. + +2. Make sure you have the latest version of necessary packages: + + pip install --upgrade setuptools wheel twine + +3. Create a source and binary distributions of the new version: + + python setup.py sdist bdist_wheel && twine check dist/* + + Fix any errors you get. + +4. Upload the source distribution to PyPI: + + twine upload dist/* + +5. Commit any outstanding changes: + + git commit -a + git push + +6. Tag the new release of the project on GitHub with the version number from + the `setup.py` file. For example if the version number in `setup.py` is + 0.0.1 then do: + + git tag 0.0.1 + git push --tags + +## License + +[AGPL](https://www.gnu.org/licenses/agpl-3.0.en.html) diff --git a/compose/2.10/src/ckanext-d4science/ckanext/__init__.py b/compose/2.10/src/ckanext-d4science/ckanext/__init__.py new file mode 100644 index 0000000..ed48ed0 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/__init__.py @@ -0,0 +1,9 @@ +# encoding: utf-8 + +# this is a namespace package +try: + import pkg_resources + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/__init__.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/.gitignore b/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/script.js b/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/script.js new file mode 100644 index 0000000..19cbb55 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/script.js @@ -0,0 +1,10 @@ +ckan.module("d4science-module", function ($, _) { + "use strict"; + return { + options: { + debug: false, + }, + + initialize: function () {}, + }; +}); diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/style.css b/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/style.css new file mode 100644 index 0000000..9631595 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/style.css @@ -0,0 +1,5 @@ +/* +body { + border-radius: 0; +} +*/ diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/webassets.yml b/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/webassets.yml new file mode 100644 index 0000000..6efc58d --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/assets/webassets.yml @@ -0,0 +1,14 @@ +# d4science-js: +# filter: rjsmin +# output: ckanext-d4science/%(version)s-d4science.js +# contents: +# - js/d4science.js +# extra: +# preload: +# - base/main + +# d4science-css: +# filter: cssrewrite +# output: ckanext-d4science/%(version)s-d4science.css +# contents: +# - css/d4science.css diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/cli.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/cli.py new file mode 100644 index 0000000..060483e --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/cli.py @@ -0,0 +1,20 @@ +import click + + +@click.group(short_help="d4science CLI.") +def d4science(): + """d4science CLI. + """ + pass + + +@d4science.command() +@click.argument("name", default="d4science") +def command(name): + """Docs. + """ + click.echo("Hello, {name}!".format(name=name)) + + +def get_commands(): + return [d4science] diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/helpers.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/helpers.py new file mode 100644 index 0000000..98b7f2d --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/helpers.py @@ -0,0 +1,9 @@ + +def d4science_hello(): + return "Hello, d4science!" + + +def get_helpers(): + return { + "d4science_hello": d4science_hello, + } diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/i18n/.gitignore b/compose/2.10/src/ckanext-d4science/ckanext/d4science/i18n/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/action.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/action.py new file mode 100644 index 0000000..abd4970 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/action.py @@ -0,0 +1,25 @@ +import ckan.plugins.toolkit as tk +import ckanext.d4science.logic.schema as schema + + +@tk.side_effect_free +def d4science_get_sum(context, data_dict): + tk.check_access( + "d4science_get_sum", context, data_dict) + data, errors = tk.navl_validate( + data_dict, schema.d4science_get_sum(), context) + + if errors: + raise tk.ValidationError(errors) + + return { + "left": data["left"], + "right": data["right"], + "sum": data["left"] + data["right"] + } + + +def get_actions(): + return { + 'd4science_get_sum': d4science_get_sum, + } diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/auth.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/auth.py new file mode 100644 index 0000000..346bef3 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/auth.py @@ -0,0 +1,12 @@ +import ckan.plugins.toolkit as tk + + +@tk.auth_allow_anonymous_access +def d4science_get_sum(context, data_dict): + return {"success": True} + + +def get_auth_functions(): + return { + "d4science_get_sum": d4science_get_sum, + } diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/schema.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/schema.py new file mode 100644 index 0000000..f5c4191 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/schema.py @@ -0,0 +1,11 @@ +import ckan.plugins.toolkit as tk + + +def d4science_get_sum(): + not_empty = tk.get_validator("not_empty") + convert_int = tk.get_validator("convert_int") + + return { + "left": [not_empty, convert_int], + "right": [not_empty, convert_int] + } diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/validators.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/validators.py new file mode 100644 index 0000000..8a7e597 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/logic/validators.py @@ -0,0 +1,13 @@ +import ckan.plugins.toolkit as tk + + +def d4science_required(value): + if not value or value is tk.missing: + raise tk.Invalid(tk._("Required")) + return value + + +def get_validators(): + return { + "d4science_required": d4science_required, + } diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/plugin.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/plugin.py new file mode 100644 index 0000000..06eb5a5 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/plugin.py @@ -0,0 +1,77 @@ +import ckan.plugins as plugins +import ckan.plugins.toolkit as toolkit +from ckan.views.resource import Blueprint +from ckanext.d4science import helpers +from ckanext.d4science.logic import action, auth +from ckanext.d4science.logic import validators + + +# import ckanext.d4science.cli as cli +# import ckanext.d4science.helpers as helpers +# import ckanext.d4science.views as views +# from ckanext.d4science.logic import ( +# action, auth, validators +# ) + + +class D4SciencePlugin(plugins.SingletonPlugin): + plugins.implements(plugins.IConfigurer) + + plugins.implements(plugins.IAuthFunctions) + plugins.implements(plugins.IActions) + # plugins.implements(plugins.IClick) + plugins.implements(plugins.ITemplateHelpers) + plugins.implements(plugins.IValidators) + + #ckan 2.10 + plugins.implements(plugins.IBlueprint) + + + # IConfigurer + + def update_config(self, config_): + toolkit.add_template_directory(config_, "templates") + toolkit.add_public_directory(config_, "public") + toolkit.add_resource("assets", "d4science") + + + # IAuthFunctions + + def get_auth_functions(self): + return auth.get_auth_functions() + + # IActions + + def get_actions(self): + return action.get_actions() + + # IBlueprint + + # def get_blueprint(self): + # return views.get_blueprints() + + def get_blueprint(self): + blueprint = Blueprint('foo', self.__module__) + # rules = [ + # ('/group', 'group_index', custom_group_index), + # ] + # for rule in rules: + # blueprint.add_url_rule(*rule) + + return blueprint + + # IClick + + # def get_commands(self): + # return cli.get_commands() + + # ITemplateHelpers + + def get_helpers(self): + return helpers.get_helpers() + + # IValidators + + def get_validators(self): + return validators.get_validators() + diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/public/.gitignore b/compose/2.10/src/ckanext-d4science/ckanext/d4science/public/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/templates/.gitignore b/compose/2.10/src/ckanext-d4science/ckanext/d4science/templates/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/__init__.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_action.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_action.py new file mode 100644 index 0000000..4983727 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_action.py @@ -0,0 +1,13 @@ +"""Tests for action.py.""" + +import pytest + +import ckan.tests.helpers as test_helpers + + +@pytest.mark.ckan_config("ckan.plugins", "d4science") +@pytest.mark.usefixtures("with_plugins") +def test_d4science_get_sum(): + result = test_helpers.call_action( + "d4science_get_sum", left=10, right=30) + assert result["sum"] == 40 diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_auth.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_auth.py new file mode 100644 index 0000000..183d32b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_auth.py @@ -0,0 +1,19 @@ +"""Tests for auth.py.""" + +import pytest + +import ckan.tests.factories as factories +import ckan.tests.helpers as test_helpers +import ckan.model as model + + +@pytest.mark.ckan_config("ckan.plugins", "d4science") +@pytest.mark.usefixtures("with_request_context", "with_plugins", "clean_db") +def test_d4science_get_sum(): + user = factories.User() + context = { + "user": user["name"], + "model": model + } + assert test_helpers.call_auth( + "d4science_get_sum", context=context) diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_validators.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_validators.py new file mode 100644 index 0000000..6c7f28e --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/logic/test_validators.py @@ -0,0 +1,16 @@ +"""Tests for validators.py.""" + +import pytest + +import ckan.plugins.toolkit as tk + +from ckanext.d4science.logic import validators + + +def test_d4science_reauired_with_valid_value(): + assert validators.d4science_required("value") == "value" + + +def test_d4science_reauired_with_invalid_value(): + with pytest.raises(tk.Invalid): + validators.d4science_required(None) diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_helpers.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_helpers.py new file mode 100644 index 0000000..f90d94b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_helpers.py @@ -0,0 +1,7 @@ +"""Tests for helpers.py.""" + +import ckanext.d4science.helpers as helpers + + +def test_d4science_hello(): + assert helpers.d4science_hello() == "Hello, d4science!" diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_plugin.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_plugin.py new file mode 100644 index 0000000..ee3f39f --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_plugin.py @@ -0,0 +1,56 @@ +""" +Tests for plugin.py. + +Tests are written using the pytest library (https://docs.pytest.org), and you +should read the testing guidelines in the CKAN docs: +https://docs.ckan.org/en/2.9/contributing/testing.html + +To write tests for your extension you should install the pytest-ckan package: + + pip install pytest-ckan + +This will allow you to use CKAN specific fixtures on your tests. + +For instance, if your test involves database access you can use `clean_db` to +reset the database: + + import pytest + + from ckan.tests import factories + + @pytest.mark.usefixtures("clean_db") + def test_some_action(): + + dataset = factories.Dataset() + + # ... + +For functional tests that involve requests to the application, you can use the +`app` fixture: + + from ckan.plugins import toolkit + + def test_some_endpoint(app): + + url = toolkit.url_for('myblueprint.some_endpoint') + + response = app.get(url) + + assert response.status_code == 200 + + +To temporary patch the CKAN configuration for the duration of a test you can use: + + import pytest + + @pytest.mark.ckan_config("ckanext.myext.some_key", "some_value") + def test_some_action(): + pass +""" +import ckanext.d4science.plugin as plugin + + +@pytest.mark.ckan_config("ckan.plugins", "d4science") +@pytest.mark.usefixtures("with_plugins") +def test_plugin(): + assert plugin_loaded("d4science") diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_views.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_views.py new file mode 100644 index 0000000..9f12530 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/tests/test_views.py @@ -0,0 +1,16 @@ +"""Tests for views.py.""" + +import pytest + +import ckanext.d4science.validators as validators + + +import ckan.plugins.toolkit as tk + + +@pytest.mark.ckan_config("ckan.plugins", "d4science") +@pytest.mark.usefixtures("with_plugins") +def test_d4science_blueprint(app, reset_db): + resp = app.get(tk.h.url_for("d4science.page")) + assert resp.status_code == 200 + assert resp.body == "Hello, d4science!" diff --git a/compose/2.10/src/ckanext-d4science/ckanext/d4science/views.py b/compose/2.10/src/ckanext-d4science/ckanext/d4science/views.py new file mode 100644 index 0000000..7192356 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/ckanext/d4science/views.py @@ -0,0 +1,17 @@ +from flask import Blueprint + + +d4science = Blueprint( + "d4science", __name__) + + +def page(): + return "Hello, d4science!" + + +d4science.add_url_rule( + "/d4science/page", view_func=page) + + +def get_blueprints(): + return [d4science] diff --git a/compose/2.10/src/ckanext-d4science/dev-requirements.txt b/compose/2.10/src/ckanext-d4science/dev-requirements.txt new file mode 100644 index 0000000..eac82b4 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/dev-requirements.txt @@ -0,0 +1 @@ +pytest-ckan diff --git a/compose/2.10/src/ckanext-d4science/requirements.txt b/compose/2.10/src/ckanext-d4science/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science/setup.cfg b/compose/2.10/src/ckanext-d4science/setup.cfg new file mode 100644 index 0000000..94cc26d --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/setup.cfg @@ -0,0 +1,62 @@ +[metadata] +name = ckanext-d4science +version = 0.0.1 +description = d4science custom extensions +long_description = file: README.md +long_description_content_type = text/markdown +url = https://github.com/d4science/ckanext-d4science +author = d4science +author_email = info@d4science.org +license = AGPL +classifiers = + Development Status :: 4 - Beta + License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+) + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 +keywords = CKAN + +[options] +packages = find: +namespace_packages = ckanext +install_requires = +include_package_data = True + +[options.entry_points] +ckan.plugins = + d4science = ckanext.d4science.plugin:D4SciencePlugin + +babel.extractors = + ckan = ckan.lib.extract:extract_ckan + +[options.extras_require] + +[extract_messages] +keywords = translate isPlural +add_comments = TRANSLATORS: +output_file = ckanext/d4science/i18n/ckanext-d4science.pot +width = 80 + +[init_catalog] +domain = ckanext-d4science +input_file = ckanext/d4science/i18n/ckanext-d4science.pot +output_dir = ckanext/d4science/i18n + +[update_catalog] +domain = ckanext-d4science +input_file = ckanext/d4science/i18n/ckanext-d4science.pot +output_dir = ckanext/d4science/i18n +previous = true + +[compile_catalog] +domain = ckanext-d4science +directory = ckanext/d4science/i18n +statistics = true + +[tool:pytest] +filterwarnings = + ignore::sqlalchemy.exc.SADeprecationWarning + ignore::sqlalchemy.exc.SAWarning + ignore::DeprecationWarning +addopts = --ckan-ini test.ini diff --git a/compose/2.10/src/ckanext-d4science/setup.py b/compose/2.10/src/ckanext-d4science/setup.py new file mode 100644 index 0000000..4d26df7 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/setup.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +from setuptools import setup + +setup( + # If you are changing from the default layout of your extension, you may + # have to change the message extractors, you can read more about babel + # message extraction at + # http://babel.pocoo.org/docs/messages/#extraction-method-mapping-and-configuration + message_extractors={ + 'ckanext': [ + ('**.py', 'python', None), + ('**.js', 'javascript', None), + ('**/templates/**.html', 'ckan', None), + ], + } +) diff --git a/compose/2.10/src/ckanext-d4science/test.ini b/compose/2.10/src/ckanext-d4science/test.ini new file mode 100644 index 0000000..67f9d4b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science/test.ini @@ -0,0 +1,45 @@ +[DEFAULT] +debug = false +smtp_server = localhost +error_email_from = ckan@localhost + +[app:main] +use = config:../../src/ckan/test-core.ini + +# Insert any custom config settings to be used when running your extension's +# tests here. These will override the one defined in CKAN core's test-core.ini +ckan.plugins = d4science + + +# Logging configuration +[loggers] +keys = root, ckan, sqlalchemy + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console + +[logger_ckan] +qualname = ckan +handlers = +level = INFO + +[logger_sqlalchemy] +handlers = +qualname = sqlalchemy.engine +level = WARN + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s diff --git a/compose/2.10/src/ckanext-d4science_theme/.project b/compose/2.10/src/ckanext-d4science_theme/.project new file mode 100644 index 0000000..2c4c958 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/.project @@ -0,0 +1,17 @@ + + + ckanext-d4science_theme + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/compose/2.10/src/ckanext-d4science_theme/.settings/org.eclipse.core.resources.prefs b/compose/2.10/src/ckanext-d4science_theme/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..77f221a --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/setup.py=utf-8 diff --git a/compose/2.10/src/ckanext-d4science_theme/LICENSE b/compose/2.10/src/ckanext-d4science_theme/LICENSE new file mode 100644 index 0000000..3ffc567 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/LICENSE @@ -0,0 +1,661 @@ +GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/MANIFEST.in b/compose/2.10/src/ckanext-d4science_theme/MANIFEST.in new file mode 100644 index 0000000..06e4a8a --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/MANIFEST.in @@ -0,0 +1,2 @@ +include README.rst +recursive-include ckanext/d4science_theme *.html *.json *.js *.less *.css \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/README.rst b/compose/2.10/src/ckanext-d4science_theme/README.rst new file mode 100644 index 0000000..ebc903a --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/README.rst @@ -0,0 +1,129 @@ + +============ +ckanext-d4science_theme +============ + +The CKAN extension that implements the D4Science theme template used by D4Science Catalogues + + +------------ +Requirements +------------ + +None + +------------ +Installation +------------ + +To install ckanext-d4science_theme: + +1. Activate your CKAN virtual environment, for example:: + + . /usr/lib/ckan/default/bin/activate + +2. Install the ckanext-d4science_theme Python package into your virtual environment:: + + pip install ckanext-d4science_theme + +3. Add ``d4science_theme`` to the ``ckan.plugins`` setting in your CKAN + config file (by default the config file is located at + ``/etc/ckan/default/production.ini``). + +4. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu:: + + sudo service apache2 reload + + +--------------- +Config Settings +--------------- + +Document any optional config settings here. For example:: + + # The minimum number of hours to wait before re-checking a resource + # (optional, default: 24). + ckanext.d4science_theme.some_setting = some_default_value + + +------------------------ +Development Installation +------------------------ + +To install ckanext-d4science_theme for development, activate your CKAN virtualenv and +do:: + + git clone https://code-repo.d4science.org/CKAN-Extensions/ckanext-d4science_theme.git + cd ckanext-d4science_theme + python setup.py develop + pip install -r dev-requirements.txt + + +----------------- +Running the Tests +----------------- + +To run the tests, do:: + + nosetests --nologcapture --with-pylons=test.ini + +To run the tests and produce a coverage report, first make sure you have +coverage installed in your virtualenv (``pip install coverage``) then run:: + + nosetests --nologcapture --with-pylons=test.ini --with-coverage --cover-package=ckanext.d4science_theme --cover-inclusive --cover-erase --cover-tests + + +--------------------------------- +Registering ckanext-d4science_theme on PyPI +--------------------------------- + +ckanext-d4science_theme should be availabe on PyPI as +https://pypi.python.org/pypi/ckanext-d4science_theme. If that link doesn't work, then +you can register the project on PyPI for the first time by following these +steps: + +1. Create a source distribution of the project:: + + python setup.py sdist + +2. Register the project:: + + python setup.py register + +3. Upload the source distribution to PyPI:: + + python setup.py sdist upload + +4. Tag the first release of the project on GitHub with the version number from + the ``setup.py`` file. For example if the version number in ``setup.py`` is + 0.0.1 then do:: + + git tag 0.0.1 + git push --tags + + +---------------------------------------- +Releasing a New Version of ckanext-d4science_theme +---------------------------------------- + +ckanext-d4science_theme is availabe on PyPI as https://pypi.python.org/pypi/ckanext-d4science_theme. +To publish a new version to PyPI follow these steps: + +1. Update the version number in the ``setup.py`` file. + See `PEP 440 `_ + for how to choose version numbers. + +2. Create a source distribution of the new version:: + + python setup.py sdist + +3. Upload the source distribution to PyPI:: + + python setup.py sdist upload + +4. Tag the new release of the project on GitHub with the version number from + the ``setup.py`` file. For example if the version number in ``setup.py`` is + 0.0.2 then do:: + + git tag 0.0.2 + git push --tags diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/__init__.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/__init__.py new file mode 100644 index 0000000..2e2033b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/__init__.py @@ -0,0 +1,7 @@ +# this is a namespace package +try: + import pkg_resources + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/__init__.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/__init__.py new file mode 100644 index 0000000..6cca9de --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/__init__.py @@ -0,0 +1,19 @@ +# from flask import Flask, g +# from ckan.lib.app_globals import app_globals +# import ckan.plugins.toolkit as toolkit + +# app = Flask("d4Science") + +# def base_context(): +# return { +# 'helpers': toolkit.h, +# } + +# @app.context_processor +# def inject_base_context(): +# return base_context() + +# # Aggiungi main_css al contesto globale di Flask +# # @app.before_request +# # def before_request(): +# # g.main_css = app_globals.main_css \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/css/d4science_theme.css b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/css/d4science_theme.css new file mode 100644 index 0000000..9e416b1 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/css/d4science_theme.css @@ -0,0 +1,844 @@ +/* ===================================================== + The "account masthead" bar across the top of the site + ===================================================== */ + +.account-masthead { + background-color: #ccc; +} +/* The "bubble" containing the number of new notifications. */ +.account-masthead .account .notifications a span { + background-color: #9fa0a2; +} +/* The text and icons in the user account info. */ +.account-masthead .account ul li a { + color: rgba(255, 255, 255, 0.6); +} +/* The user account info text and icons, when the user's pointer is hovering + over them. */ +.account-masthead .account ul li a:hover { + color: rgba(255, 255, 255, 0.7); +/* background-color: black;*/ +} + + +/* ======================================================================== + The main masthead bar that contains the site logo, nav links, and search + ======================================================================== */ + +.masthead { + background: #eee url("/bg-noise.png") repeat scroll 0 0; + border-top: 1px solid #555; + padding-top: 5px; + padding-bottom: 15px !important; + border-bottom: 1px solid #999; +/* background-image: url("/bg-pattern.min.svg") !important; */ +} + +.masthead .navigation .nav-pills li a{ + color: #187794; +} + +a.logo > img{ + margin-bottom: 5px; +} + +/* The "navigation pills" in the masthead (the links to Datasets, + Organizations, etc) when the user's pointer hovers over them. */ +.masthead .navigation .nav-pills li a:hover { +/* background-color: rgb(48, 48, 48);*/ + color: white; +} +/* The "active" navigation pill (for example, when you're on the /dataset page + the "Datasets" link is active). */ +.masthead .navigation .nav-pills li.active a { + background-color: #d2d2d5; +} +/* The "box shadow" effect that appears around the search box when it + has the keyboard cursor's focus. */ +.masthead input[type="text"]:focus { + -webkit-box-shadow: inset 0px 0px 2px 0px rgba(0, 0, 0, 0.7); + box-shadow: inset 0px 0px 2px 0px rgba(0, 0, 0, 0.7); +} + + +/* =========================================== + The content in the middle of the front page + =========================================== */ + +/* Remove the "box shadow" effect around various boxes on the page. */ +.box { + box-shadow: none; +} +.hero { + background: #FEFEFE repeat scroll 0 0 !important; +} +/* Remove the borders around the "Welcome to CKAN" and "Search Your Data" + boxes. */ +.hero .box { + /*border: none;*/ + margin-top: 10px !important; +} +/* Change the colors of the "Search Your Data" box. */ +.homepage .module-search .module-content { + color: rgb(68, 68, 68); + background-color: white; +} +/* Change the background color of the "Popular Tags" box. */ +.homepage .module-search .tags { + background-color: #fcfcfc; +} + +.homepage-title{ + font-size: 20px; + font-weight: bold; + color: #202020; + margin-bottom: 20px; +} + +/* Change the background color of the "Popular Tags" box. */ +.homepage .module-search h3{ + color: #444; +} + +/* Remove some padding. This makes the bottom edges of the "Welcome to CKAN" + and "Search Your Data" boxes line up. */ +.module-content:last-child { + /*padding-bottom: 0px;*/ +} +.homepage .module-search { + padding: 0px; +} +/* Add a border line between the top and bottom halves of the front page. */ +.homepage [role="main"] { + border-bottom: 1px solid #bbb; + padding: 10px 0; +} + +.homepage .stats ul li a b{ + font-size: 30px !important; +} + +[role="main"], .main { +/* background: #f5f6fa url("/bg-pattern.min.svg") repeat; scroll 0 0;*/ + /*background: #fafafa url("/bg-pattern.svg") repeat; scroll 0 0;*/ + background: #fdfdfd none repeat scroll 0 0; + min-height: 0px !important; +} + +.media-item-homepage { + background-color: white; + border-radius: 3px; + float: left; + margin: 15px 0 0 15px; + overflow: hidden; + padding-left: 10px; + padding-right: 10px; + position: relative; + text-align: center; + width: 150px; +} + +.media-heading-homepage { + font-size: 16px; + hyphens: auto; + line-height: 1.3; + margin: 5px 0; +} + +.media-grid-homepage { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; +/* background: #fbfbfb url("../../../base/images/bg.png") repeat scroll 0 0; + border-color: #dddddd; + border-image: none; + border-style: solid; + border-width: 1px 0;*/ + list-style: outside none none; + margin: 0 -10px; + padding-bottom: 15px; +} +.media-grid-homepage::before, .media-grid::after { + content: ""; + display: table; + line-height: 0; +} +.media-grid-homepage::after { + clear: both; +} + +.background-circle{ + padding: 10px 10px; + display: inline-block !important; + -webkit-border-radius: 90px; + -moz-border-radius: 90px; + border-radius: 90px; + background-color: #4679b2; + text-decoration: none !important; +} + +.color-white{ + color: white !important; +} + +.badge-circle { + border-radius: 50% 50% 50% 50% !important; + height: 60px; + text-align: center; + vertical-align: middle; + width: 65px; + background-color: #4679b2; + display: inline-block !important; + padding-top: 5px; + text-decoration: none !important; +} + +/* ==================================== + The footer at the bottom of the site + ==================================== */ + +.site-footer, body { + background-color: #bbb; + font-family: "Lato","Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 16px; +} +/* The text in the footer. */ +.site-footer, +.site-footer label, +.site-footer small { + color: rgba(255, 255, 255, 0.6); +} +/* The link texts in the footer. */ +.site-footer a { + color: rgba(255, 255, 255, 0.6); +} + +.site-footer-internal{ + min-height: 10px; + padding: 2px 0; + font-size: 12px; +} + +.site-footer-internal { + /*background-color: rgba(255, 255, 255, 0.6);*/ + text-align: center; + /*display: inline-block;*/ +} + +.site-footer-internal, +.site-footer-internal label, +.site-footer-internal small { + +} + +.site-footer-internal a { + display: inline-block; +} + +.d4s-hide-text { + background-color: transparent; + border: 0 none; + color: transparent; + font: 0px/0 a; + text-shadow: none; +} + +.d4science-footer-logo { + background: url("/gCube_70.png") no-repeat scroll left top rgba(0, 0, 0, 0); + height: 32px; + margin-top: 2px; + text-indent: -900em; + width: 75px; +} + +.d4s-ckan-footer-logo { + background: rgba(0, 0, 0, 0) url("/ckan-logo-footer.png") no-repeat scroll left top; + height: 21px; + margin-top: 2px; + text-indent: -900em; + width: 69px; +} + +.site-footer-d4science { + font-size: 14px; + color: #f5f5f5; + text-align: center; + height: 25px; + padding-top: 5px; + background-color: #7F7F7F; +} + +.site-footer-d4science a { + font-weight: bold; + text-decoration: none; + color: white; +} + + +/* ==================================== + Base elements of the site + ==================================== */ + +div .principaltitle { + color: inherit; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 20px; + font-weight: bold; + line-height: 1.2; + margin: 15px 0; + text-rendering: optimizelegibility; + word-break: break-all; + padding-bottom: 10px; + padding-top: 5px; + border-bottom: 1px solid #eee; +} + +div .notes { + color: #444444; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 14px; + line-height: 1.3; + text-align: justify; + word-break: break-all; +} + +div .infotitle { + font-size: 15px; + hyphens: auto; + line-height: 1.3; + word-break: break-all; + font-weight: bold; +} + +.toolbar .breadcrumb{ + font-size: 16px !important; +} + +.box{ + border: 0px !important; +} + +div .sectiontitle{ + color: #9F9F9F; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 17px; + font-weight: bold; + margin: 20px 0; + margin-top: 20px; + margin-bottom: 10px; + text-rendering: optimizelegibility; +} + +section .well { + background-color: #fdfdfd !important; + border: 1px solid #e3e3e3; + border-radius: 4px; + box-shadow: none !important; + margin-bottom: 20px; + min-height: 20px; + +} + +.page-heading { + font-size: 18px; + line-height: 1.2; + margin-top: 20px; + margin-bottom: 0px; +} + +#dataset-resources .resource-list{ + background-color: #fdfdfd !important; + border: 1px solid #e3e3e3; + border-radius: 4px; + box-shadow: none !important; + margin: -1px 0 !important; +} + +.wrapper{ + border: 1px solid #d0d0d0; + box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.05); + border-radius: 3px +} + +.home-popular{ + padding-top: 25px; +} + +.logo-homepage{ + max-height: 60px; +} + +.statistics-show{ + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + color: #444444; + text-decoration: none; +} + +.d4s-center-cropped{ + text-align: center; + background-color: #eee; + border: 1px solid #ddd; + padding-bottom: 10px; + padding-top: 10px; +} + +.tag-list { + font-size: 14px; +} + + +/* ==================================== + Acquired Dataset + ==================================== */ +.label-acquired { + background-color: #55a1ce; +} + +.label-owner { + background-color: #e0051e; +} + +.divider { + margin-left:10px; + height:auto; + display:inline-block; +} + +/* ==================================== + List Dataset + ==================================== */ + +/*LEFT +.show_meatadatatype { + color: white; + display: inline-block; // Inline elements with width and height. TL;DR they make the icon buttons stack from left-to-right instead of top-to-bottom + position: relative; // All 'absolute'ly positioned elements are relative to this one + margin-bottom: 20px; + margin-left: 25px; +} +*/ + +/*RIGHT*/ +.show_meatadatatype { + color: white; + display: inline-block; + float: right; + margin-right: 2px; + margin-top: -20px; + position: relative; +} + + + +/* LEFT + * Position the badge within the relatively positioned button +.button__badge { + background-color: #fa3e3e; + border-radius: 2px; + color: white; + + padding: 1px 6px; + font-size: 10px; + + position: absolute; + top: 0; + right: 0; +}*/ + + + +/* RIGTH */ +.button__badge { + color: #808080; + padding: 0px 2px; + font-size: 10px; + top: 0; + right: 0; + font-family: sans-serif, times, georgia; +} + +/* ==================================== + Modal Popup + ==================================== */ + +/* Popup container - can be anything you want */ +/* The Modal (background) */ +.d4s_modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 10001; /* Sit on top (NB. At 1000 there is the zoom in/out of the Map Widget)*/ + /*padding-top: 100px;*/ /* Location of the box */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + +/* Modal Content */ +.d4s_modal-content { + background-color: #fefefe; + /*margin: auto;*/ + padding: 20px; + border: 1px solid #888; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + position: absolute; + left: 50%; + margin-left: -225px; + width: 450px; +} + +/* The Close Button */ +.d4s_close { + color: #aaaaaa; + float: right; + font-size: 28px; + font-weight: bold; + padding-left: 20px; +} + +.d4s_close:hover, +.d4s_close:focus { + color: #000; + text-decoration: none; + cursor: pointer; +} + +.d4s_div_clickable{ + cursor: pointer; +} + +/*==================================== +D4S POPUP +======================================*/ + +/* Popup container - can be anything you want */ +.popupD4SNoArrow { + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* The actual popup */ +.popupD4SNoArrow .popuptext { + visibility: hidden; + width: 300px; + background-color: #555; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 8px; + position: absolute; + z-index: 1; + bottom: 125%; + left: 50%; + margin-left: -150px; +} + +/* Toggle this class - hide and show the popup */ +.popupD4SNoArrow .show { + visibility: visible; + -webkit-animation: fadeIn 1s; + animation: fadeIn 1s; +} + + +/* Popup container - can be anything you want */ +.popupD4S { + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* The actual popup */ +.popupD4S .popuptext { + visibility: hidden; + width: 300px; + background-color: #555; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 8px; + position: absolute; + z-index: 1; + bottom: 125%; + left: 50%; + margin-left: -150px; +} + +/* Popup arrow */ +.popupD4S .popuptext::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: #555 transparent transparent transparent; +} + +/* Toggle this class - hide and show the popup */ +.popupD4S .show { + visibility: visible; + -webkit-animation: fadeIn 1s; + animation: fadeIn 1s; +} + +/* Add animation (fade in the popup) */ +@-webkit-keyframes fadeIn { + from {opacity: 0;} + to {opacity: 1;} +} + +@keyframes fadeIn { + from {opacity: 0;} + to {opacity:1 ;} +} + +/*==================================== +D4S PACKAGE +======================================*/ + +.graphic-preview-style { + text-align: center; + border-top: 1px dotted #DDD; + padding-top: 10px; + padding-bottom: 0px; + margin-top: 15px; +} + +.graphic-preview-style a{ + font-size: 13px; +} + +.graphic-preview-style img{ + max-width: 100% !important; + height: auto; + +} + +.graphic-preview-style #graphic-title{ + font-size: 13px; + +} + +.nav-item{ + word-wrap:break-word; + } + +/*==================================== +RESOURCE_LIST RESOURCE_ITEM INTO PACKAGE +======================================*/ + +.required-access { + font-style: italic; + font-weight: bold; + padding: 5px; +} + +/*==================================== +LINK TO RESOURCES FROM PACKAGE LIST +======================================*/ + +.dataset-resources li a { + background-color: #187794; +} + +.label[data-format="csw"], .label[data-format*="csw"] { + background-color: #e6b800; +} + +/*==================================== +CSS APPLIED TO Similar GRSF Records +======================================*/ + +.my-grsf-table{ + word-break: break-all; +} + +.my-grsf-table tr td{ + width: inherit; +} + +.my-grsf-table tr td:first-child{ + width: 82px !important; +} + +/*==================================== +CSS APPLIED in base.html +======================================*/ + +#ckan-page-loading { + display: none; + position: fixed; + top: 50%; + left: 50%; + margin-top: -130px; + margin-left: -130px; + width: 260px; + height: 260px; + z-index: 100000; + background-image: url("/pageloading.gif"); + background-repeat: no-repeat; + background-position: center; +} + +/*==================================== +CSS APPLIED in search_for_location.html +======================================*/ + +div#search-for-location { + +} + +div#search-for-location #dataset-map { + position: relative !important; + top: +0px !important; +} + +div#search-for-location #dataset-map-container { + height: 300px; +} + + +div#search-for-location .module-heading { + display: none; +} + +div#search-for-extent{ + padding-top: 10px; +} + +/*==================================== +CSS APPLIED in additional_info.html +======================================*/ +.qr-code-table { + width: 100%; +} + +.qr-code-table td { + width: 85%; + border: 1px solid #e3e3e3; +} + +.qr-code-table td:first-child { + padding-left: 10px; + border-right-style: none; + +} + +.qr-code-table td:last-child { + width: 105px; + text-align: center; + border-left-style: none; + +} + +/* MAX-WITH APPIED TO QR_CODE */ +.qr-code-table img { + max-width: 100px; + height: auto; +} + + +/*==================================== +CSS APPLIED FROM JSON TO HTML TABLE +======================================*/ + +.json-to-html-table-column{ + word-break: break-all; +} + +.json-to-html-table-column tr td{ + width: inherit; +} + +.json-to-html-table-column tr td:first-child{ + font-weight: bold; + color: #5a5a5a; +} + +/*==================================== +CSS APPLIED into custom_form_fields +======================================*/ +.disabled-div{ + pointer-events: none; + opacity: 0.5; +} + +.disabled-div input[type="text"]{ + background: #f1f1f1; +} + +/*==================================== +CSS APPLIED into extra_table.html +======================================*/ + +.read-more-state { + display: none; +} + +.read-more-target { + opacity: 0; + max-height: 0; + font-size: 0; + transition: .25s ease; +} + +.read-more-state:checked ~ .read-more-wrap .read-more-target { + opacity: 1; + font-size: inherit; + max-height: 999em; + content: ""; +} + +.read-more-state ~ .read-more-trigger:before { + content: 'Show more'; +} + +.read-more-state:checked ~ .read-more-trigger:before { + content: 'Show less'; +} + +.read-more-state:checked ~ .read-more-wrap::after { + content: ""; +} + +.read-more-trigger { + cursor: pointer; + display: inline-block; + padding: 0 .5em; + color: #187794; + font-size: .9em; + line-height: 2; + border: 1px solid #ddd; + border-radius: .25em; + font-weight: normal; +} + +.read-more-trigger::after { + content: ""; +} + +.read-more-wrap { + margin-bottom: 2px; +} + +.read-more-wrap::after{ + content: " ..."; + +} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/js/d4science_scripts.js b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/js/d4science_scripts.js new file mode 100644 index 0000000..36b79e3 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/js/d4science_scripts.js @@ -0,0 +1,305 @@ +/* ===================================================== +JavaScript used by CKAN plugin: 'd4science_theme' +Created by Francesco Mangiacrapa ISTI-CNR Pisa, Italy +===================================================== */ + + +//old script starts +CKAN_D4S_Breadcrumb_Manager = { + + breadcrumbShow : function (show) { + + var breadcrumb = document.getElementById('ckan-breadcrumb'); + console.log('breadcrumb is '+breadcrumb) + if(breadcrumb){ + if(show){ + breadcrumb.style.display = 'block'; + this.organizationTreeShow(true); + } else{ + breadcrumb.style.display = 'none'; + this.organizationTreeShow(false); + } + } + + //var elements = document.getElementsByTagName('a'); + //for(var i = 0, len = elements.length; i < len; i++) { + // elements[i].onclick = function () { + // //alert("You clicked an external link to: " + this.href); + // //window.parent.add_hide_breadcrumb_to_dom(false); + // this.add_hide_breadcrumb_to_dom(false); + // } + //} + }, + + organizationTreeShow : function (show) { + var trees = document.getElementsByClassName("hierarchy-tree-top"); + + if (trees){ + for (i = 0; i < trees.length; i++) { + if(show){ + trees[i].style.display = 'block'; + } else{ + trees[i].style.display = 'none'; + } + } + } + }, + + checkBreadcrumbShow : function () { + + var showBdc = this.getSessionStorageItem("showbreadcrumb") + //console.log("showBdc is: "+showBdc) + if(showBdc != undefined && showBdc=="false"){ + console.log("Show breadcrumb false"); + this.breadcrumbShow(false); + }else{ + console.log("Show breadcrumb true"); + this.breadcrumbShow(true); + } + }, + + + setSessionStorageItem : function (item_key, item_value) { + + // Check browser support + if (typeof(Storage) !== "undefined") { + // Store + sessionStorage.setItem(item_key, item_value); + return true; + } else { + console.log("Sorry, your browser does not support Web Storage..."); + return false; + } + }, + + + getSessionStorageItem : function (item_key) { + + // Check browser support + if (typeof(Storage) !== "undefined") { + // Store + return sessionStorage.getItem(item_key); + } else { + console.log("Sorry, your browser does not support Web Storage..."); + return undefined; + } + } + +} + + +CKAN_D4S_Functions_Util = { + + getPosition : function(canvas, event){ + var x = new Number(); + var y = new Number(); + try { + if (event.clientX != undefined && event.clientY != undefined) + { + + x = event.clientX; + y = event.clientY; + } + else // Firefox method to get the position + { + x = event.clientX + document.body.scrollLeft + + document.documentElement.scrollLeft; + y = event.clientY + document.body.scrollTop + + document.documentElement.scrollTop; + } + x -= canvas.offsetLeft; + y -= canvas.offsetTop; + }catch (err) { + //silent error + } + return '{"posX": "'+x+'", "posY": "'+y+'"}'; + }, + + // When the user clicks on div, open the popup + showPopupD4S : function(event, my_div, my_popup_left_position) { + var popup = document.getElementById(my_div); + var clickPosition = this.getPosition(my_div, event) + var myPosition = JSON.parse(clickPosition); + this.closePopups(my_div); + // When the user clicks anywhere outside of the modal, close it + /*window.onclick = function(event) { + if (event.target != popup) { + popup.style.display = "none"; + } + }*/ + popup.classList.toggle("show"); + + if(my_popup_left_position){ + popup.style.left = my_popup_left_position; + } + else if (myPosition.posX){ + popup.style.left = myPosition.posX + "px"; + } + }, + + closePopups : function ($target) { + var popups = document.getElementsByClassName('popuptext'); + for (i = 0; i < popups.length; i++) { + if (popups[i].getAttribute('id') != $target) { + popups[i].classList.remove('show'); + } + } + }, + + checkURL : function (url) { + //console.log('checking url: '+url) + var regex = new RegExp('^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/|www\.|ftp:\/\/)+[^ "]+$'); + if (regex.test(url)) { + return true; + } + return false; + } + +} + +CKAN_D4S_HTMLMessage_Util = { + +postHeightToPortlet : function (selectedProduct, product) { + var h = document.body.scrollHeight + "px"; + var p = ""; + var msg = ""; + //WORK AROUND IF TWO MESSAGES ARE SENT FROM A PAGE OF A PRODUCT + //THE MESSAGE WITH 'NULL' PRODUCT IS SKIPPED + //console.log("window.location.pathname? "+window.location.pathname); + var pathArray = window.location.pathname.split('/'); + var productContext = "dataset"; + if(pathArray.length>1){ + //console.log("pathArray is: "+pathArray); + var secondLevelLocation = pathArray[1]; //it is the second level location + //console.log("secondLevelLocation is: "+secondLevelLocation); + //console.log("h is: "+h); + if(secondLevelLocation == productContext){ //is it product context? + if(product !== 'undefined' && product !== null){ + p = product; + //console.log("product selected is: "+p); + }else{ + //console.log("product is null or undefined, passing only height"); + msg = "{\"height\": \""+h+"\"}"; + //window.postMessage(msg,'*'); + this.postMessageToParentWindow(msg); + return; + } + } + } + + //msg = "{'height': '"+h+"', 'product': '"+p+"'}"; + msg = "{\"height\": \""+h+"\", \"product\": \""+p+"\"}"; + //window.postMessage(msg,'*'); + //console.log("posting message in the window: "+msg); + this.postMessageToParentWindow(msg); + }, + + postMessageToParentWindow : function (msg) { + //window.postMessage(msg,'*'); + //console.log("posting message in the window: "+msg); + if(window.parent!=null){ + console.log("posting message in the parent window: "+msg); + window.parent.postMessage(msg,'*'); + } + return; + } + +} + +CKAN_D4S_JSON_Util = { + + +//ADDED by Francesco Mangiacrapa +appendHTMLToElement : function(containerID, elementHTML){ + + var divContainer = document.getElementById(containerID); + divContainer.innerHTML = ""; + divContainer.appendChild(elementHTML); +}, + +//ADDED by Francesco Mangiacrapa +jsonToHTML : function(containerID, cssClassToTable) { + + try + { + var jsonTxt = document.getElementById(containerID).innerHTML; + var jsonObj = JSON.parse(jsonTxt); + //console.log(jsonObj.length) + + if(jsonObj.length==undefined) + jsonObj = [jsonObj] + //console.log(jsonObj.length) + + // EXTRACT VALUE FOR HTML HEADER. + var col = []; + for (var i = 0; i < jsonObj.length; i++) { + for (var key in jsonObj[i]) { + //console.log('key json' +key) + if (col.indexOf(key) === -1) { + col.push(key); + } + } + } + + // CREATE DYNAMIC TABLE. + var table = document.createElement("table"); + var addDefaultCss = "json-to-html-table-column"; + if(cssClassToTable){ + addDefaultCss = cssClassToTable; + } + try{ + table.classList.add(addDefaultCss); + }catch(e){ + console.log('invalid css add', e); + } + + // ADD JSON DATA TO THE TABLE AS ROWS. + for (var i = 0; i < col.length; i++) { + + tr = table.insertRow(-1); + var firstCell = tr.insertCell(-1); + //firstCell.style.cssText="font-weight: bold; text-align: center; vertical-align: middle;"; + firstCell.innerHTML = col[i]; + for (var j = 0; j < jsonObj.length; j++) { + var tabCell = tr.insertCell(-1); + var theValue = jsonObj[j][col[i]]; + /* console.log(theValue + ' is url? '+isUrl);*/ + if(CKAN_D4S_Functions_Util.checkURL(theValue)){ + theValue = ''+theValue+''; + } + + tabCell.innerHTML = theValue; + } + } + + // FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER. + this.appendHTMLToElement(containerID, table); + + } + catch(e){ + console.log('invalid json', e); + } +} +} + + +//Task #8032 +window.addEventListener("message", +function (e) { + + var curr_loc = window.location.toString() + var orgin = e.origin.toString() + if(curr_loc.startsWith(orgin)){ + //alert("ignoring message from myself"); + return; + } + //console.log("origin: "+e.data) + if(e.data == null) + return; + + var pMess = JSON.parse(e.data) + //console.log(pMess.explore_vres_landing_page) + window.linktogateway = pMess.explore_vres_landing_page; +},false); +//old script ends + \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/webassets.yml b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/webassets.yml new file mode 100644 index 0000000..5b697a1 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/assets/webassets.yml @@ -0,0 +1,15 @@ +d4science-js: + filter: rjsmin + output: ckanext-d4science_theme/ckanext/d4science_theme/assets/js/d4science_scripts.js + contents: + - js/d4science_scripts.js + extra: + preload: + - base/main + +d4science-css: + filter: cssrewrite + output: ckanext-d4science_theme/ckanext/d4science_theme/assets/css/d4science_theme.css + contents: + - css/d4science_theme.css + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/__init__.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/__init__.py new file mode 100644 index 0000000..68f2e01 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/__init__.py @@ -0,0 +1,4 @@ +#The __init__.py files are required to make Python +#treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. +#See: https://docs.python.org/3/tutorial/modules.html#packages + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/home.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/home.py new file mode 100644 index 0000000..c5746d5 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/home.py @@ -0,0 +1,83 @@ +import logging +# from ckan.controllers.home import HomeController +import ckan.plugins as p +from ckan.common import _, g, c +from collections import OrderedDict + +import ckan.lib.search as search +import ckan.model as model +import ckan.logic as logic +import ckan.lib.maintain as maintain +import ckan.lib.base as base +import ckan.lib.helpers as h + +from flask import render_template + + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +class d4SHomeController(): + + #Overriding controllers.HomeController.index method + def index(self): + try: + # package search + context = {'model': model, 'session': model.Session,'user': c.user, 'auth_user_obj': c.userobj} + + facets = OrderedDict() + + default_facet_titles = { + 'organization': _('Organizations'), + 'groups': _('Groups'), + 'types':_('Types'), + 'tags': _('Tags'), + 'res_format': _('Formats'), + 'license_id': _('Licenses'), + } + + for facet in g.facets: + if facet in default_facet_titles: + facets[facet] = default_facet_titles[facet] + else: + facets[facet] = facet + + # Facet titles + for plugin in p.PluginImplementations(p.IFacets): + facets = plugin.dataset_facets(facets, 'dataset') + + c.facet_titles = facets + + data_dict = { + 'q': '*:*', + 'facet.field': list(facets.keys()), + 'rows': 4, + 'start': 0, + 'sort': 'views_recent desc', + 'fq': 'capacity:"public"' + } + query = logic.get_action('package_search')(context, data_dict) + c.search_facets = query['search_facets'] + c.package_count = query['count'] + c.datasets = query['results'] + + #print "c.search_facets: " + #print " ".join(c.search_facets) + + except search.SearchError: + c.package_count = 0 + + if c.userobj and not c.userobj.email: + url = h.url_for(controller='user', action='edit') + msg = _('Please update your profile' + ' and add your email address. ') % url + \ + _('%s uses your email address' + ' if you need to reset your password.') \ + % g.site_title + h.flash_notice(msg, allow_html=True) + + #return base.render('home/index.html', cache_force=True) + #ckan 2.10 : + return render_template('home/index.html') + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/organization.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/organization.py new file mode 100644 index 0000000..90b85cc --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/organization.py @@ -0,0 +1,134 @@ +# encoding: utf-8 + +import re + +#import ckan.controllers.group as group +import ckan.plugins as plugins +import logging +import datetime +from urllib.parse import urlencode + +import ckan.plugins.toolkit as toolkit +import ckan.lib.base as base +import ckan.lib.helpers as h +import ckan.lib.maintain as maintain +import ckan.lib.navl.dictization_functions as dict_fns +import ckan.logic as logic +import ckan.lib.search as search +import ckan.model as model +import ckan.authz as authz +import ckan.lib.plugins +import ckan.plugins as plugins +from ckan.common import c, request, _ + + +''' +Created by Francesco Mangiacrapa, see: #8964 +''' +class OrganizationVREController(plugins.toolkit.DefaultOrganizationForm): #changed for 2.10 : GroupController -> defaultOrganizationForm + ''' The organization controller is for Organizations, which are implemented + as Groups with is_organization=True and group_type='organization'. It works + the same as the group controller apart from: + * templates and logic action/auth functions are sometimes customized + (switched using _replace_group_org) + * 'bulk_process' action only works for organizations + + Nearly all the code for both is in the GroupController (for historical + reasons). + ''' + + group_types = ['organization'] + + def _guess_group_type(self, expecting_name=False): + return 'organization' + + def _replace_group_org(self, string): + ''' substitute organization for group if this is an org''' + return re.sub('^group', 'organization', string) + + def _update_facet_titles(self, facets, group_type): + for plugin in plugins.PluginImplementations(plugins.IFacets): + facets = plugin.organization_facets( + facets, group_type, None) + + def index(self): + group_type = self._guess_group_type() + + page = h.get_page_number(request.args) or 1 + items_per_page = 21 + + context = {'model': model, 'session': model.Session, + 'user': c.user, 'for_view': True, + 'with_private': False} + + q = c.q = request.args.get('q', '') + sort_by = c.sort_by_selected = request.args.get('sort') + try: + logic.check_access('site_read', context) + logic.check_access('group_list', context) + except ckan.plugins.toolkit.NotAuthorized: + abort(403, _('Not authorized to see this page')) + + # pass user info to context as needed to view private datasets of + # orgs correctly + if c.userobj: + context['user_id'] = c.userobj.id + context['user_is_admin'] = c.userobj.sysadmin + + data_dict_global_results = { + 'all_fields': False, + 'q': q, + 'sort': sort_by, + 'type': group_type or 'group', + } + global_results = toolkit.get_action('group_list')(context, + data_dict_global_results) + + data_dict_page_results = { + 'all_fields': True, + 'q': q, + 'sort': sort_by, + 'type': group_type or 'group', + 'limit': items_per_page, + 'offset': items_per_page * (page - 1), + } + page_results = toolkit.get_action('group_list')(context, + data_dict_page_results) + + c.page = h.Page( + collection=global_results, + page=page, + url=h.pager_url, + items_per_page=items_per_page, + ) + + c.page.items = page_results + return base.render('organization_vre/index.html', + extra_vars={'group_type': group_type}) + + + def read(self, id, limit=20): + group_type = self._ensure_controller_matches_group_type( + id.split('@')[0]) + + context = {'model': model, 'session': model.Session, + 'user': c.user, + 'schema': self._db_to_form_schema(group_type=group_type), + 'for_view': True} + data_dict = {'id': id, 'type': group_type} + + # unicode format (decoded from utf8) + c.q = request.args.get('q', '') + + try: + # Do not query for the group datasets when dictizing, as they will + # be ignored and get requested on the controller anyway + data_dict['include_datasets'] = False + c.group_dict = toolkit.get_action('group_show')(context, data_dict) + c.group = context['group'] + except (NotFound, NotAuthorized, ckan.logic.NotFound): + abort(404, _('Group not found')) + + self._read(id, limit, group_type) + return base.render('organization_vre/read.html', + extra_vars={'group_type': group_type}) \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/systemtype.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/systemtype.py new file mode 100644 index 0000000..8d94e5b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/controllers/systemtype.py @@ -0,0 +1,96 @@ +import logging +import ckan.plugins as p +from ckan.common import _, g, c +import ckan.lib.search as search +import ckan.model as model +import ckan.logic as logic +import ckan.lib.maintain as maintain +import ckan.lib.base as base +import ckan.lib.helpers as h + +from urllib.parse import urlencode + + +import ckan.lib.base as base +import ckan.lib.helpers as h +import ckan.lib.maintain as maintain +import ckan.lib.navl.dictization_functions as dict_fns +import ckan.logic as logic +import ckan.lib.search as search +import ckan.model as model +import ckan.authz as authz +import ckan.lib.plugins +import ckan.plugins as plugins +from ckan.common import c, g, request, _ + +from collections import OrderedDict +from flask import render_template + + + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +class d4STypeController(): + + #Overriding controllers.HomeController.index method + def index(self): + try: + # package search + context = {'model': model, 'session': model.Session,'user': c.user, 'auth_user_obj': c.userobj} + + facets = OrderedDict() + + default_facet_titles = { + 'organization': _('Organizations'), + 'groups': _('Groups'), + 'types':_('Types'), + 'tags': _('Tags'), + 'res_format': _('Formats'), + 'license_id': _('Licenses'), + } + + for facet in g.facets: + if facet in default_facet_titles: + facets[facet] = default_facet_titles[facet] + else: + facets[facet] = facet + + # Facet titles + for plugin in p.PluginImplementations(p.IFacets): + facets = plugin.dataset_facets(facets, 'dataset') + + c.facet_titles = facets + + data_dict = { + 'q': '*:*', + 'facet.field': list(facets.keys()), + 'rows': 4, + 'start': 0, + 'sort': 'views_recent desc', + 'fq': 'capacity:"public"' + } + query = logic.get_action('package_search')(context, data_dict) + c.search_facets = query['search_facets'] + c.package_count = query['count'] + c.datasets = query['results'] + + #print "c.search_facets: " + #print " ".join(c.search_facets) + + except search.SearchError: + c.package_count = 0 + + if c.userobj and not c.userobj.email: + url = h.url_for(controller='user', action='edit') + msg = _('Please update your profile' + ' and add your email address. ') % url + \ + _('%s uses your email address' + ' if you need to reset your password.') \ + % g.site_title + h.flash_notice(msg, allow_html=True) + + # return base.render('type/index.html', cache_force=True) + return render_template('type/index.html') + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/__init__.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_cache_controller.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_cache_controller.py new file mode 100644 index 0000000..0462d7d --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_cache_controller.py @@ -0,0 +1,106 @@ +import datetime +import logging +import os +import tempfile +import csv + +from .icproxycontroller import NAMESPACE_ID_LABEL + +log = logging.getLogger(__name__) + +CATALINA_HOME = 'CATALINA_HOME' +temp_dir = None +namespaces_dir = None +NAMESPACES_DIR_NAME = "namespaces_for_catalogue" +NAMESPACES_CACHE_FILENAME = "Namespaces_Catalogue_Categories.csv" + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + + +# D4S_Cache_Controller +class D4S_Cache_Controller(): + namespaces_cache_path = None + __scheduler = None + + def __init__(self): + """ Virtually private constructor. """ + log.debug("__init__ D4S_Cache_Controller") + self._check_cache() + + def _check_cache(self): + + if self.namespaces_cache_path is None: + self.init_temp_dir() + self.namespaces_cache_path = os.path.join(namespaces_dir, NAMESPACES_CACHE_FILENAME) + log.info("The namespaces cache is located at: %s" % self.namespaces_cache_path) + + if not os.path.exists(self.namespaces_cache_path): + log.info("File does not exists creating it") + try: + with open(self.namespaces_cache_path, mode='w') as namespaces_file: + csv.writer(namespaces_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) + log.info("Cache created at %s" % self.namespaces_cache_path) + except Exception as e: + print(e) + + ''' Write the list of dictionary with namespaces''' + def write_namespaces(self, namespace_list_of_dict): + # Insert Data + with open(self.namespaces_cache_path, 'w') as namespaces_file: + writer = csv.writer(namespaces_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) + writer.writerow([NAMESPACE_ID_LABEL, 'name', 'title', 'description']) + for namespace_dict in namespace_list_of_dict: + #print("namespace %s" % namespace_dict) + writer.writerow([namespace_dict[NAMESPACE_ID_LABEL], namespace_dict['name'], namespace_dict['title'], namespace_dict['description']]) + + log.info("Inserted %d namespaces in the Cache" % len(namespace_list_of_dict)) + + '''Returns the list of dictionary with namespaces''' + def read_namespaces(self): + # Read Data + namespace_list_of_dict = [] + try: + with open(self.namespaces_cache_path, 'r') as namespaces_file: + reader = csv.DictReader(namespaces_file) + for row in reader: + #print("read namespace %s" % row) + namespace_list_of_dict.append(dict(row)) + + log.debug("from Cache returning namespace_list_of_dict %s: " % namespace_list_of_dict) + log.info("from Cache read namespace_list_of_dict with %d item/s " % len(namespace_list_of_dict)) + return namespace_list_of_dict + except Exception as e: + print(e) + + log.info("no namespace in the Cache returning empty list of dict") + return namespace_list_of_dict + + @property + def get_namespaces_cache_path(self): + return self.namespaces_cache_path + + @classmethod + def init_temp_dir(cls): + global temp_dir + global NAMESPACES_DIR_NAME + global namespaces_dir + try: + temp_dir = str(os.environ[CATALINA_HOME]) + temp_dir = os.path.join(temp_dir, "temp") + except KeyError as error: + log.error("No environment variable for: %s" % CATALINA_HOME) + + if temp_dir is None: + temp_dir = tempfile.gettempdir() # using system tmp dir + + log.debug("Temp dir is: %s" % temp_dir) + + namespaces_dir = os.path.join(temp_dir, NAMESPACES_DIR_NAME) + + if not os.path.exists(namespaces_dir): + os.makedirs(namespaces_dir) + + + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_extras.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_extras.py new file mode 100644 index 0000000..8a62764 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_extras.py @@ -0,0 +1,30 @@ +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +import logging +log = logging.getLogger(__name__) + +class D4S_Extras(): + + def __init__(self, category_dict={}, extras=[]): + self._category = category_dict + self._extras = extras + + def append_extra(self, k, v): + #print ("self._extras: %s" %self._extras) + if k is not None: + self._extras.append({k:v}) + + @property + def category(self): + return self._category + + @property + def extras(self): + return self._extras + + def __repr__(self): + return 'category: %s'%self._category+' ' \ + 'extras: %s'%self._extras + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces.py new file mode 100644 index 0000000..54f1e90 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces.py @@ -0,0 +1,39 @@ +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +#OrderedDict([(u'@id', u'extra_information'), (u'name', u'Extra Information'), (u'title', u'Extras'), (u'description', u'This section is about Extra(s)')]), u'contact': OrderedDict([(u'@id', u'contact'), (u'name', u'Contact'), (u'title', u'Contact Title'), (u'description', u'This section is about Contact(s)')]), u'developer_information': OrderedDict([(u'@id', u'developer_information'), (u'name', u'Developer'), (u'title', u'Developer Information'), (u'description', u'This section is about Developer(s)')])} + +import logging +log = logging.getLogger(__name__) + +class D4S_Namespaces(): + + def __init__(self, id=None, name=None, title=None, description=None): + self._id = id + self._name = name + self._title = title + self._description = description + + @property + def id(self): + return self._id + + @property + def name(self): + return self._name + + @property + def title(self): + return self._title + + + @property + def description(self): + return self._description + + def __repr__(self): + return '{id: %s'%self.id+', ' \ + 'name: %s'%self.name+ ', ' \ + 'title: %s'%self.title+ ', ' \ + 'description: %s'%self.description+ '}' diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_controller.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_controller.py new file mode 100644 index 0000000..afb88df --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_controller.py @@ -0,0 +1,130 @@ +import logging +import time + +from .d4s_cache_controller import D4S_Cache_Controller +from .icproxycontroller import D4S_IS_DiscoveryCatalogueNamespaces +from threading import Event, Thread + +CATEGORY = 'category' +NOCATEOGORY = 'nocategory' + +log = logging.getLogger(__name__) + +cancel_future_calls = None + +# Refreshing time for namespaces cache in secs. +NAMESPACES_CACHE_REFRESHING_TIME = 60 * 60 + + +# Funtion to call repeatedly another function +def call_repeatedly(interval, func, *args): + log.info("call_repeatedly called on func '{}' with interval {} sec".format(func.__name__, interval)) + stopped = Event() + + def loop(): + while not stopped.wait(interval): # the first call is in `interval` secs + func(*args) + + th = Thread(name='daemon_caching_namespaces', target=loop) + th.setDaemon(True) + th.start() + return stopped.set + + +def reload_namespaces_from_IS(urlICProxy, resourceID, gcubeToken): + log.info("_reload_namespaces_from_IS called") + try: + discovery_ctg_namespaces = D4S_IS_DiscoveryCatalogueNamespaces(urlICProxy, resourceID, gcubeToken) + namespaces_list_of_dict = discovery_ctg_namespaces.getNamespacesDictFromResource() + + if namespaces_list_of_dict is not None and len(namespaces_list_of_dict) > 0: + log.debug("namespaces read from IS are: %s" % namespaces_list_of_dict) + D4S_Cache_Controller().write_namespaces(namespaces_list_of_dict) + else: + log.info("namespaces list read from IS is empty. Skipping caching update") + + except Exception as e: + print("Error occurred on reading namespaces from IS and refilling the cache!") + print(e) + + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + + +# D4S_IS_DiscoveryCatalogueNamespacesController is used to discovery namespaces for Catalogue Categories (implemented as a Singleton) +# @param: urlICProxy is the URI of IC proxy rest-full service provided by IS +# @param: resourceID is the resource ID of the Generic Resource: "Namespaces Catalogue Categories" +# @param: gcubeToken the gcube token used to contact the IC proxy +class D4S_Namespaces_Controller(): + __instance = None + + @staticmethod + def getInstance(): + """ Static access method. """ + if D4S_Namespaces_Controller.__instance is None: + D4S_Namespaces_Controller() + + return D4S_Namespaces_Controller.__instance + + def __init__(self): + """ Virtually private constructor. """ + log.debug("__init__ D4S_Namespaces_Controller") + + if D4S_Namespaces_Controller.__instance is not None: + raise Exception("This class is a singleton!") + else: + D4S_Namespaces_Controller.__instance = self + + self._d4s_cache_controller = D4S_Cache_Controller() + self._urlICProxy = None + self._resourceID = None + self._gcubeToken = None + + def load_namespaces(self, urlICProxy, resourceID, gcubeToken): + log.debug("readNamespaces called") + self._urlICProxy = urlICProxy + self._resourceID = resourceID + self._gcubeToken = gcubeToken + return self._check_namespaces() + + def _read_namespaces(self): + return self._d4s_cache_controller.read_namespaces() + + def _check_namespaces(self): + log.debug("_check_namespaces called") + + if self._d4s_cache_controller is None: + self._d4s_cache_controller = D4S_Cache_Controller() + + namespace_list = self._read_namespaces() + + # when the Cache is empty + if namespace_list is None or not namespace_list: + # reading namespaces from IS and filling the DB + log.info("The Cache is empty. Reading the namespace from IS and filling the Cache") + reload_namespaces_from_IS(self._urlICProxy, self._resourceID, self._gcubeToken) + # reloading the namespaces from the cache + namespace_list = self._read_namespaces() + + # starting Thread daemon for refreshing the namespaces Cache + global cancel_future_calls + if cancel_future_calls is None: + cancel_future_calls = call_repeatedly(NAMESPACES_CACHE_REFRESHING_TIME, reload_namespaces_from_IS, + self._urlICProxy, + self._resourceID, + self._gcubeToken) + + return namespace_list + + def get_dict_ctg_namespaces(self): + log.debug("get_dict_ctg_namespaces called") + namespace_list_of_dict = self._check_namespaces() + return self.convert_namespaces_to_d4s_namespacedict(namespace_list_of_dict) + + # Private method + @staticmethod + def convert_namespaces_to_d4s_namespacedict(namespace_list_of_dict): + log.debug("convert_namespaces_to_d4s_namespacedict called on %s" % namespace_list_of_dict) + return D4S_IS_DiscoveryCatalogueNamespaces.to_namespaces_dict_index_for_id(namespace_list_of_dict) diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_extras_util.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_extras_util.py new file mode 100644 index 0000000..edb0bbf --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_extras_util.py @@ -0,0 +1,89 @@ +import logging +import collections +from .d4s_extras import D4S_Extras + +CATEGORY = 'category' +NOCATEOGORY = 'nocategory' + +log = logging.getLogger(__name__) + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + + +# D4S_Namespaces_Extra_Util is used to get the extra fields indexed for D4Science namespaces +# @param: namespace_dict is the namespace dict of D4Science namespaces (defined in the Generic Resource: "Namespaces Catalogue Categories") +# @param: extras is the dictionary of extra fields for a certain item +class D4S_Namespaces_Extra_Util(): + + def get_extras_indexed_for_namespaces(self, namespace_dict, extras): + extras_for_categories = collections.OrderedDict() + + # ADDING ALL EXTRAS WITH NAMESPACE + for namespaceid in list(namespace_dict.keys()): + dict_extras = None + nms = namespaceid + ":" + #has_namespace_ref = None + for key, value in extras: + k = key + v = value + # print "key: " + k + # print "value: " + v + if k.startswith(nms): + + if namespaceid not in extras_for_categories: + extras_for_categories[namespaceid] = collections.OrderedDict() + + dict_extras = extras_for_categories[namespaceid] + log.debug("dict_extras %s "%dict_extras) + + if (dict_extras is None) or (not dict_extras): + dict_extras = D4S_Extras(namespace_dict.get(namespaceid), []) + log.debug("dict_extras after init %s " % dict_extras) + + #print ("dict_extras after init %s " % dict_extras) + log.debug("replacing namespace into key %s " % k +" with empty string") + nms = namespaceid + ":" + k = k.replace(nms, "") + dict_extras.append_extra(k, v) + extras_for_categories[namespaceid] = dict_extras + log.debug("adding d4s_extra: %s " % dict_extras+ " - to namespace id: %s" %namespaceid) + #has_namespace_ref = True + #break + + #ADDING ALL EXTRAS WITHOUT NAMESPACE + for key, value in extras: + k = key + v = value + + has_namespace_ref = None + for namespaceid in list(namespace_dict.keys()): + nms = namespaceid + ":" + #IF KEY NOT STARTING WITH NAMESPACE + if k.startswith(nms): + has_namespace_ref = True + log.debug("key: %s " % k + " - have namespace: %s" % nms) + break + + if has_namespace_ref is None: + log.debug("key: %s " % k + " - have not namespace") + if NOCATEOGORY not in extras_for_categories: + extras_for_categories[NOCATEOGORY] = collections.OrderedDict() + + dict_extras_no_cat = extras_for_categories[NOCATEOGORY] + #print ("dict_extras_no_cat %s " % dict_extras_no_cat) + + if (dict_extras_no_cat is None) or (not dict_extras_no_cat): + dict_extras_no_cat = D4S_Extras(NOCATEOGORY, []) + + #print ("adding key: %s "%k+" - value: %s"%v) + log.debug("NOCATEOGORY adding key: %s " % k + " - value: %s" % v) + + dict_extras_no_cat.append_extra(k, v) + log.debug("dict_extras_no_cat %s " % dict_extras_no_cat) + extras_for_categories[NOCATEOGORY] = dict_extras_no_cat + log.debug("extras_for_categories NOCATEOGORY %s " % extras_for_categories) + + return extras_for_categories + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/icproxycontroller.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/icproxycontroller.py new file mode 100644 index 0000000..f1c03ce --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/d4sdiscovery/icproxycontroller.py @@ -0,0 +1,110 @@ +import logging +import urllib.request, urllib.error, urllib.parse +from lxml import etree + +import xmltodict +import collections + +from .d4s_namespaces import D4S_Namespaces + +XPATH_NAMESPACES = "/Resource/Profile/Body/namespaces" +gcubeTokenParam = "gcube-token" +NAMESPACE_ID_LABEL = '@id' + +log = logging.getLogger(__name__) + + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +def getResponseBody(uri): + req = urllib.request.Request(uri) + try: + resp = urllib.request.urlopen(req, timeout=20) + except urllib.error.HTTPError as e: + log.error("Error on contacting URI: %s" % uri) + log.error("HTTPError: %d" % e.code) + return None + except urllib.error.URLError as e: + # Not an HTTP-specific error (e.g. connection refused) + log.error("URLError - Input URI: %s " % uri + " is not valid!!") + return None + else: + # 200 + body = resp.read() + return body + + +# D4S_IS_DiscoveryCatalogueNamespaces is used to discovery namespaces for Catalogue Categories. +# @param: urlICProxy is the URI of IC proxy rest-full service provided by IS +# @param: resourceID is the resource ID of the Generic Resource: "Namespaces Catalogue Categories" +# @param: gcubeToken the gcube token used to contact the IC proxy +class D4S_IS_DiscoveryCatalogueNamespaces(): + + def __init__(self, urlICProxy, resourceID, gcubeToken): + self.urlICProxy = urlICProxy + self.resourceID = resourceID + self.gcubeToken = gcubeToken + + def getNamespacesDictFromResource(self): + + doc = {} + namespace_list = [] + + try: + # print("proxy: "+self.urlICProxy) + # print("resourceID: " + self.resourceID) + # print("gcubeTokenParam: " + gcubeTokenParam) + # print("gcubeToken: " + self.gcubeToken) + + uri = self.urlICProxy + "/" + self.resourceID + "?" + gcubeTokenParam + "=" + self.gcubeToken + log.info("Contacting URL: %s" % uri) + theResource = getResponseBody(uri) + log.debug("Resource returned %s " % theResource) + theResourceXML = etree.XML(theResource) + theNamespaces = theResourceXML.xpath(XPATH_NAMESPACES) + log.debug("The body %s" % etree.tostring(theNamespaces[0])) + + if theNamespaces is not None and theNamespaces[0] is not None: + bodyToString = etree.tostring(theNamespaces[0]) + doc = xmltodict.parse(bodyToString) + else: + log.warn("No Namespace for Catalogue Categories found, returning None") + except Exception as inst: + log.error("Error on getting catalogue namespaces: " + str(inst)) + log.info("Returning empty list of namespaces") + return namespace_list + + log.debug("IS namespaces resource to dict is: %s" % doc) + + + if ('namespaces' in doc): + # log.debug('Namespaces obj %s:' % doc['namespaces']) + namespaces = doc['namespaces'] + if doc is not None and 'namespace' in namespaces: + namespace_list = namespaces['namespace'] + + log.info("Loaded %d namespaces from IS resource" % len(namespace_list)) + return namespace_list + + @staticmethod + def to_namespaces_dict_index_for_id(namespace_list): + namespace_dict = collections.OrderedDict() + log.debug("namespaces to dict: %s" % namespace_list) + try: + if namespace_list is not None and len(namespace_list) > 0: + for namespace in namespace_list: + try: + if NAMESPACE_ID_LABEL in namespace: + namespace_dict[namespace[NAMESPACE_ID_LABEL]] = D4S_Namespaces( + namespace[NAMESPACE_ID_LABEL], + namespace['name'], + namespace['title'], + namespace['description']) + except Exception as inst: + log.error("Error on converting catalogue namespaces: " + str(inst)) + except Exception as inst: + log.error("Error on checking namespace_list: " + str(inst)) + # print "namespace_dict to Nam: %s"%namespace_dict + return namespace_dict diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/fanstatic/.gitignore b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/fanstatic/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/fanstatic/d4science_scripts.js b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/fanstatic/d4science_scripts.js new file mode 100644 index 0000000..642cdc5 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/fanstatic/d4science_scripts.js @@ -0,0 +1,303 @@ +/* ===================================================== + JavaScript used by CKAN plugin: 'd4science_theme' + Created by Francesco Mangiacrapa ISTI-CNR Pisa, Italy + ===================================================== */ + + +CKAN_D4S_Breadcrumb_Manager = { + + breadcrumbShow : function (show) { + + var breadcrumb = document.getElementById('ckan-breadcrumb'); + console.log('breadcrumb is '+breadcrumb) + if(breadcrumb){ + if(show){ + breadcrumb.style.display = 'block'; + this.organizationTreeShow(true); + } else{ + breadcrumb.style.display = 'none'; + this.organizationTreeShow(false); + } + } + + //var elements = document.getElementsByTagName('a'); + //for(var i = 0, len = elements.length; i < len; i++) { + // elements[i].onclick = function () { + // //alert("You clicked an external link to: " + this.href); + // //window.parent.add_hide_breadcrumb_to_dom(false); + // this.add_hide_breadcrumb_to_dom(false); + // } + //} + }, + + organizationTreeShow : function (show) { + var trees = document.getElementsByClassName("hierarchy-tree-top"); + + if (trees){ + for (i = 0; i < trees.length; i++) { + if(show){ + trees[i].style.display = 'block'; + } else{ + trees[i].style.display = 'none'; + } + } + } + }, + + checkBreadcrumbShow : function () { + + var showBdc = this.getSessionStorageItem("showbreadcrumb") + //console.log("showBdc is: "+showBdc) + if(showBdc != undefined && showBdc=="false"){ + console.log("Show breadcrumb false"); + this.breadcrumbShow(false); + }else{ + console.log("Show breadcrumb true"); + this.breadcrumbShow(true); + } + }, + + + setSessionStorageItem : function (item_key, item_value) { + + // Check browser support + if (typeof(Storage) !== "undefined") { + // Store + sessionStorage.setItem(item_key, item_value); + return true; + } else { + console.log("Sorry, your browser does not support Web Storage..."); + return false; + } + }, + + + getSessionStorageItem : function (item_key) { + + // Check browser support + if (typeof(Storage) !== "undefined") { + // Store + return sessionStorage.getItem(item_key); + } else { + console.log("Sorry, your browser does not support Web Storage..."); + return undefined; + } + } + +} + + +CKAN_D4S_Functions_Util = { + + getPosition : function(canvas, event){ + var x = new Number(); + var y = new Number(); + try { + if (event.clientX != undefined && event.clientY != undefined) + { + + x = event.clientX; + y = event.clientY; + } + else // Firefox method to get the position + { + x = event.clientX + document.body.scrollLeft + + document.documentElement.scrollLeft; + y = event.clientY + document.body.scrollTop + + document.documentElement.scrollTop; + } + x -= canvas.offsetLeft; + y -= canvas.offsetTop; + }catch (err) { + //silent error + } + return '{"posX": "'+x+'", "posY": "'+y+'"}'; + }, + + // When the user clicks on div, open the popup + showPopupD4S : function(event, my_div, my_popup_left_position) { + var popup = document.getElementById(my_div); + var clickPosition = this.getPosition(my_div, event) + var myPosition = JSON.parse(clickPosition); + this.closePopups(my_div); + // When the user clicks anywhere outside of the modal, close it + /*window.onclick = function(event) { + if (event.target != popup) { + popup.style.display = "none"; + } + }*/ + popup.classList.toggle("show"); + + if(my_popup_left_position){ + popup.style.left = my_popup_left_position; + } + else if (myPosition.posX){ + popup.style.left = myPosition.posX + "px"; + } + }, + + closePopups : function ($target) { + var popups = document.getElementsByClassName('popuptext'); + for (i = 0; i < popups.length; i++) { + if (popups[i].getAttribute('id') != $target) { + popups[i].classList.remove('show'); + } + } + }, + + checkURL : function (url) { + //console.log('checking url: '+url) + var regex = new RegExp('^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/|www\.|ftp:\/\/)+[^ "]+$'); + if (regex.test(url)) { + return true; + } + return false; + } + +} + +CKAN_D4S_HTMLMessage_Util = { + + postHeightToPortlet : function (selectedProduct, product) { + var h = document.body.scrollHeight + "px"; + var p = ""; + var msg = ""; + //WORK AROUND IF TWO MESSAGES ARE SENT FROM A PAGE OF A PRODUCT + //THE MESSAGE WITH 'NULL' PRODUCT IS SKIPPED + //console.log("window.location.pathname? "+window.location.pathname); + var pathArray = window.location.pathname.split('/'); + var productContext = "dataset"; + if(pathArray.length>1){ + //console.log("pathArray is: "+pathArray); + var secondLevelLocation = pathArray[1]; //it is the second level location + //console.log("secondLevelLocation is: "+secondLevelLocation); + //console.log("h is: "+h); + if(secondLevelLocation == productContext){ //is it product context? + if(product !== 'undefined' && product !== null){ + p = product; + //console.log("product selected is: "+p); + }else{ + //console.log("product is null or undefined, passing only height"); + msg = "{\"height\": \""+h+"\"}"; + //window.postMessage(msg,'*'); + this.postMessageToParentWindow(msg); + return; + } + } + } + + //msg = "{'height': '"+h+"', 'product': '"+p+"'}"; + msg = "{\"height\": \""+h+"\", \"product\": \""+p+"\"}"; + //window.postMessage(msg,'*'); + //console.log("posting message in the window: "+msg); + this.postMessageToParentWindow(msg); + }, + + postMessageToParentWindow : function (msg) { + //window.postMessage(msg,'*'); + //console.log("posting message in the window: "+msg); + if(window.parent!=null){ + console.log("posting message in the parent window: "+msg); + window.parent.postMessage(msg,'*'); + } + return; + } + +} + +CKAN_D4S_JSON_Util = { + + + //ADDED by Francesco Mangiacrapa + appendHTMLToElement : function(containerID, elementHTML){ + + var divContainer = document.getElementById(containerID); + divContainer.innerHTML = ""; + divContainer.appendChild(elementHTML); + }, + + //ADDED by Francesco Mangiacrapa + jsonToHTML : function(containerID, cssClassToTable) { + + try + { + var jsonTxt = document.getElementById(containerID).innerHTML; + var jsonObj = JSON.parse(jsonTxt); + //console.log(jsonObj.length) + + if(jsonObj.length==undefined) + jsonObj = [jsonObj] + //console.log(jsonObj.length) + + // EXTRACT VALUE FOR HTML HEADER. + var col = []; + for (var i = 0; i < jsonObj.length; i++) { + for (var key in jsonObj[i]) { + //console.log('key json' +key) + if (col.indexOf(key) === -1) { + col.push(key); + } + } + } + + // CREATE DYNAMIC TABLE. + var table = document.createElement("table"); + var addDefaultCss = "json-to-html-table-column"; + if(cssClassToTable){ + addDefaultCss = cssClassToTable; + } + try{ + table.classList.add(addDefaultCss); + }catch(e){ + console.log('invalid css add', e); + } + + // ADD JSON DATA TO THE TABLE AS ROWS. + for (var i = 0; i < col.length; i++) { + + tr = table.insertRow(-1); + var firstCell = tr.insertCell(-1); + //firstCell.style.cssText="font-weight: bold; text-align: center; vertical-align: middle;"; + firstCell.innerHTML = col[i]; + for (var j = 0; j < jsonObj.length; j++) { + var tabCell = tr.insertCell(-1); + var theValue = jsonObj[j][col[i]]; + /* console.log(theValue + ' is url? '+isUrl);*/ + if(CKAN_D4S_Functions_Util.checkURL(theValue)){ + theValue = ''+theValue+''; + } + + tabCell.innerHTML = theValue; + } + } + + // FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER. + this.appendHTMLToElement(containerID, table); + + } + catch(e){ + console.log('invalid json', e); + } + } +} + + +//Task #8032 +window.addEventListener("message", + function (e) { + + var curr_loc = window.location.toString() + var orgin = e.origin.toString() + if(curr_loc.startsWith(orgin)){ + //alert("ignoring message from myself"); + return; + } + //console.log("origin: "+e.data) + if(e.data == null) + return; + + var pMess = JSON.parse(e.data) + //console.log(pMess.explore_vres_landing_page) + window.linktogateway = pMess.explore_vres_landing_page; + },false); + \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/fanstatic/d4science_theme.css b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/fanstatic/d4science_theme.css new file mode 100644 index 0000000..9e416b1 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/fanstatic/d4science_theme.css @@ -0,0 +1,844 @@ +/* ===================================================== + The "account masthead" bar across the top of the site + ===================================================== */ + +.account-masthead { + background-color: #ccc; +} +/* The "bubble" containing the number of new notifications. */ +.account-masthead .account .notifications a span { + background-color: #9fa0a2; +} +/* The text and icons in the user account info. */ +.account-masthead .account ul li a { + color: rgba(255, 255, 255, 0.6); +} +/* The user account info text and icons, when the user's pointer is hovering + over them. */ +.account-masthead .account ul li a:hover { + color: rgba(255, 255, 255, 0.7); +/* background-color: black;*/ +} + + +/* ======================================================================== + The main masthead bar that contains the site logo, nav links, and search + ======================================================================== */ + +.masthead { + background: #eee url("/bg-noise.png") repeat scroll 0 0; + border-top: 1px solid #555; + padding-top: 5px; + padding-bottom: 15px !important; + border-bottom: 1px solid #999; +/* background-image: url("/bg-pattern.min.svg") !important; */ +} + +.masthead .navigation .nav-pills li a{ + color: #187794; +} + +a.logo > img{ + margin-bottom: 5px; +} + +/* The "navigation pills" in the masthead (the links to Datasets, + Organizations, etc) when the user's pointer hovers over them. */ +.masthead .navigation .nav-pills li a:hover { +/* background-color: rgb(48, 48, 48);*/ + color: white; +} +/* The "active" navigation pill (for example, when you're on the /dataset page + the "Datasets" link is active). */ +.masthead .navigation .nav-pills li.active a { + background-color: #d2d2d5; +} +/* The "box shadow" effect that appears around the search box when it + has the keyboard cursor's focus. */ +.masthead input[type="text"]:focus { + -webkit-box-shadow: inset 0px 0px 2px 0px rgba(0, 0, 0, 0.7); + box-shadow: inset 0px 0px 2px 0px rgba(0, 0, 0, 0.7); +} + + +/* =========================================== + The content in the middle of the front page + =========================================== */ + +/* Remove the "box shadow" effect around various boxes on the page. */ +.box { + box-shadow: none; +} +.hero { + background: #FEFEFE repeat scroll 0 0 !important; +} +/* Remove the borders around the "Welcome to CKAN" and "Search Your Data" + boxes. */ +.hero .box { + /*border: none;*/ + margin-top: 10px !important; +} +/* Change the colors of the "Search Your Data" box. */ +.homepage .module-search .module-content { + color: rgb(68, 68, 68); + background-color: white; +} +/* Change the background color of the "Popular Tags" box. */ +.homepage .module-search .tags { + background-color: #fcfcfc; +} + +.homepage-title{ + font-size: 20px; + font-weight: bold; + color: #202020; + margin-bottom: 20px; +} + +/* Change the background color of the "Popular Tags" box. */ +.homepage .module-search h3{ + color: #444; +} + +/* Remove some padding. This makes the bottom edges of the "Welcome to CKAN" + and "Search Your Data" boxes line up. */ +.module-content:last-child { + /*padding-bottom: 0px;*/ +} +.homepage .module-search { + padding: 0px; +} +/* Add a border line between the top and bottom halves of the front page. */ +.homepage [role="main"] { + border-bottom: 1px solid #bbb; + padding: 10px 0; +} + +.homepage .stats ul li a b{ + font-size: 30px !important; +} + +[role="main"], .main { +/* background: #f5f6fa url("/bg-pattern.min.svg") repeat; scroll 0 0;*/ + /*background: #fafafa url("/bg-pattern.svg") repeat; scroll 0 0;*/ + background: #fdfdfd none repeat scroll 0 0; + min-height: 0px !important; +} + +.media-item-homepage { + background-color: white; + border-radius: 3px; + float: left; + margin: 15px 0 0 15px; + overflow: hidden; + padding-left: 10px; + padding-right: 10px; + position: relative; + text-align: center; + width: 150px; +} + +.media-heading-homepage { + font-size: 16px; + hyphens: auto; + line-height: 1.3; + margin: 5px 0; +} + +.media-grid-homepage { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; +/* background: #fbfbfb url("../../../base/images/bg.png") repeat scroll 0 0; + border-color: #dddddd; + border-image: none; + border-style: solid; + border-width: 1px 0;*/ + list-style: outside none none; + margin: 0 -10px; + padding-bottom: 15px; +} +.media-grid-homepage::before, .media-grid::after { + content: ""; + display: table; + line-height: 0; +} +.media-grid-homepage::after { + clear: both; +} + +.background-circle{ + padding: 10px 10px; + display: inline-block !important; + -webkit-border-radius: 90px; + -moz-border-radius: 90px; + border-radius: 90px; + background-color: #4679b2; + text-decoration: none !important; +} + +.color-white{ + color: white !important; +} + +.badge-circle { + border-radius: 50% 50% 50% 50% !important; + height: 60px; + text-align: center; + vertical-align: middle; + width: 65px; + background-color: #4679b2; + display: inline-block !important; + padding-top: 5px; + text-decoration: none !important; +} + +/* ==================================== + The footer at the bottom of the site + ==================================== */ + +.site-footer, body { + background-color: #bbb; + font-family: "Lato","Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 16px; +} +/* The text in the footer. */ +.site-footer, +.site-footer label, +.site-footer small { + color: rgba(255, 255, 255, 0.6); +} +/* The link texts in the footer. */ +.site-footer a { + color: rgba(255, 255, 255, 0.6); +} + +.site-footer-internal{ + min-height: 10px; + padding: 2px 0; + font-size: 12px; +} + +.site-footer-internal { + /*background-color: rgba(255, 255, 255, 0.6);*/ + text-align: center; + /*display: inline-block;*/ +} + +.site-footer-internal, +.site-footer-internal label, +.site-footer-internal small { + +} + +.site-footer-internal a { + display: inline-block; +} + +.d4s-hide-text { + background-color: transparent; + border: 0 none; + color: transparent; + font: 0px/0 a; + text-shadow: none; +} + +.d4science-footer-logo { + background: url("/gCube_70.png") no-repeat scroll left top rgba(0, 0, 0, 0); + height: 32px; + margin-top: 2px; + text-indent: -900em; + width: 75px; +} + +.d4s-ckan-footer-logo { + background: rgba(0, 0, 0, 0) url("/ckan-logo-footer.png") no-repeat scroll left top; + height: 21px; + margin-top: 2px; + text-indent: -900em; + width: 69px; +} + +.site-footer-d4science { + font-size: 14px; + color: #f5f5f5; + text-align: center; + height: 25px; + padding-top: 5px; + background-color: #7F7F7F; +} + +.site-footer-d4science a { + font-weight: bold; + text-decoration: none; + color: white; +} + + +/* ==================================== + Base elements of the site + ==================================== */ + +div .principaltitle { + color: inherit; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 20px; + font-weight: bold; + line-height: 1.2; + margin: 15px 0; + text-rendering: optimizelegibility; + word-break: break-all; + padding-bottom: 10px; + padding-top: 5px; + border-bottom: 1px solid #eee; +} + +div .notes { + color: #444444; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 14px; + line-height: 1.3; + text-align: justify; + word-break: break-all; +} + +div .infotitle { + font-size: 15px; + hyphens: auto; + line-height: 1.3; + word-break: break-all; + font-weight: bold; +} + +.toolbar .breadcrumb{ + font-size: 16px !important; +} + +.box{ + border: 0px !important; +} + +div .sectiontitle{ + color: #9F9F9F; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 17px; + font-weight: bold; + margin: 20px 0; + margin-top: 20px; + margin-bottom: 10px; + text-rendering: optimizelegibility; +} + +section .well { + background-color: #fdfdfd !important; + border: 1px solid #e3e3e3; + border-radius: 4px; + box-shadow: none !important; + margin-bottom: 20px; + min-height: 20px; + +} + +.page-heading { + font-size: 18px; + line-height: 1.2; + margin-top: 20px; + margin-bottom: 0px; +} + +#dataset-resources .resource-list{ + background-color: #fdfdfd !important; + border: 1px solid #e3e3e3; + border-radius: 4px; + box-shadow: none !important; + margin: -1px 0 !important; +} + +.wrapper{ + border: 1px solid #d0d0d0; + box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.05); + border-radius: 3px +} + +.home-popular{ + padding-top: 25px; +} + +.logo-homepage{ + max-height: 60px; +} + +.statistics-show{ + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + color: #444444; + text-decoration: none; +} + +.d4s-center-cropped{ + text-align: center; + background-color: #eee; + border: 1px solid #ddd; + padding-bottom: 10px; + padding-top: 10px; +} + +.tag-list { + font-size: 14px; +} + + +/* ==================================== + Acquired Dataset + ==================================== */ +.label-acquired { + background-color: #55a1ce; +} + +.label-owner { + background-color: #e0051e; +} + +.divider { + margin-left:10px; + height:auto; + display:inline-block; +} + +/* ==================================== + List Dataset + ==================================== */ + +/*LEFT +.show_meatadatatype { + color: white; + display: inline-block; // Inline elements with width and height. TL;DR they make the icon buttons stack from left-to-right instead of top-to-bottom + position: relative; // All 'absolute'ly positioned elements are relative to this one + margin-bottom: 20px; + margin-left: 25px; +} +*/ + +/*RIGHT*/ +.show_meatadatatype { + color: white; + display: inline-block; + float: right; + margin-right: 2px; + margin-top: -20px; + position: relative; +} + + + +/* LEFT + * Position the badge within the relatively positioned button +.button__badge { + background-color: #fa3e3e; + border-radius: 2px; + color: white; + + padding: 1px 6px; + font-size: 10px; + + position: absolute; + top: 0; + right: 0; +}*/ + + + +/* RIGTH */ +.button__badge { + color: #808080; + padding: 0px 2px; + font-size: 10px; + top: 0; + right: 0; + font-family: sans-serif, times, georgia; +} + +/* ==================================== + Modal Popup + ==================================== */ + +/* Popup container - can be anything you want */ +/* The Modal (background) */ +.d4s_modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 10001; /* Sit on top (NB. At 1000 there is the zoom in/out of the Map Widget)*/ + /*padding-top: 100px;*/ /* Location of the box */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + +/* Modal Content */ +.d4s_modal-content { + background-color: #fefefe; + /*margin: auto;*/ + padding: 20px; + border: 1px solid #888; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + position: absolute; + left: 50%; + margin-left: -225px; + width: 450px; +} + +/* The Close Button */ +.d4s_close { + color: #aaaaaa; + float: right; + font-size: 28px; + font-weight: bold; + padding-left: 20px; +} + +.d4s_close:hover, +.d4s_close:focus { + color: #000; + text-decoration: none; + cursor: pointer; +} + +.d4s_div_clickable{ + cursor: pointer; +} + +/*==================================== +D4S POPUP +======================================*/ + +/* Popup container - can be anything you want */ +.popupD4SNoArrow { + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* The actual popup */ +.popupD4SNoArrow .popuptext { + visibility: hidden; + width: 300px; + background-color: #555; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 8px; + position: absolute; + z-index: 1; + bottom: 125%; + left: 50%; + margin-left: -150px; +} + +/* Toggle this class - hide and show the popup */ +.popupD4SNoArrow .show { + visibility: visible; + -webkit-animation: fadeIn 1s; + animation: fadeIn 1s; +} + + +/* Popup container - can be anything you want */ +.popupD4S { + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* The actual popup */ +.popupD4S .popuptext { + visibility: hidden; + width: 300px; + background-color: #555; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 8px; + position: absolute; + z-index: 1; + bottom: 125%; + left: 50%; + margin-left: -150px; +} + +/* Popup arrow */ +.popupD4S .popuptext::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: #555 transparent transparent transparent; +} + +/* Toggle this class - hide and show the popup */ +.popupD4S .show { + visibility: visible; + -webkit-animation: fadeIn 1s; + animation: fadeIn 1s; +} + +/* Add animation (fade in the popup) */ +@-webkit-keyframes fadeIn { + from {opacity: 0;} + to {opacity: 1;} +} + +@keyframes fadeIn { + from {opacity: 0;} + to {opacity:1 ;} +} + +/*==================================== +D4S PACKAGE +======================================*/ + +.graphic-preview-style { + text-align: center; + border-top: 1px dotted #DDD; + padding-top: 10px; + padding-bottom: 0px; + margin-top: 15px; +} + +.graphic-preview-style a{ + font-size: 13px; +} + +.graphic-preview-style img{ + max-width: 100% !important; + height: auto; + +} + +.graphic-preview-style #graphic-title{ + font-size: 13px; + +} + +.nav-item{ + word-wrap:break-word; + } + +/*==================================== +RESOURCE_LIST RESOURCE_ITEM INTO PACKAGE +======================================*/ + +.required-access { + font-style: italic; + font-weight: bold; + padding: 5px; +} + +/*==================================== +LINK TO RESOURCES FROM PACKAGE LIST +======================================*/ + +.dataset-resources li a { + background-color: #187794; +} + +.label[data-format="csw"], .label[data-format*="csw"] { + background-color: #e6b800; +} + +/*==================================== +CSS APPLIED TO Similar GRSF Records +======================================*/ + +.my-grsf-table{ + word-break: break-all; +} + +.my-grsf-table tr td{ + width: inherit; +} + +.my-grsf-table tr td:first-child{ + width: 82px !important; +} + +/*==================================== +CSS APPLIED in base.html +======================================*/ + +#ckan-page-loading { + display: none; + position: fixed; + top: 50%; + left: 50%; + margin-top: -130px; + margin-left: -130px; + width: 260px; + height: 260px; + z-index: 100000; + background-image: url("/pageloading.gif"); + background-repeat: no-repeat; + background-position: center; +} + +/*==================================== +CSS APPLIED in search_for_location.html +======================================*/ + +div#search-for-location { + +} + +div#search-for-location #dataset-map { + position: relative !important; + top: +0px !important; +} + +div#search-for-location #dataset-map-container { + height: 300px; +} + + +div#search-for-location .module-heading { + display: none; +} + +div#search-for-extent{ + padding-top: 10px; +} + +/*==================================== +CSS APPLIED in additional_info.html +======================================*/ +.qr-code-table { + width: 100%; +} + +.qr-code-table td { + width: 85%; + border: 1px solid #e3e3e3; +} + +.qr-code-table td:first-child { + padding-left: 10px; + border-right-style: none; + +} + +.qr-code-table td:last-child { + width: 105px; + text-align: center; + border-left-style: none; + +} + +/* MAX-WITH APPIED TO QR_CODE */ +.qr-code-table img { + max-width: 100px; + height: auto; +} + + +/*==================================== +CSS APPLIED FROM JSON TO HTML TABLE +======================================*/ + +.json-to-html-table-column{ + word-break: break-all; +} + +.json-to-html-table-column tr td{ + width: inherit; +} + +.json-to-html-table-column tr td:first-child{ + font-weight: bold; + color: #5a5a5a; +} + +/*==================================== +CSS APPLIED into custom_form_fields +======================================*/ +.disabled-div{ + pointer-events: none; + opacity: 0.5; +} + +.disabled-div input[type="text"]{ + background: #f1f1f1; +} + +/*==================================== +CSS APPLIED into extra_table.html +======================================*/ + +.read-more-state { + display: none; +} + +.read-more-target { + opacity: 0; + max-height: 0; + font-size: 0; + transition: .25s ease; +} + +.read-more-state:checked ~ .read-more-wrap .read-more-target { + opacity: 1; + font-size: inherit; + max-height: 999em; + content: ""; +} + +.read-more-state ~ .read-more-trigger:before { + content: 'Show more'; +} + +.read-more-state:checked ~ .read-more-trigger:before { + content: 'Show less'; +} + +.read-more-state:checked ~ .read-more-wrap::after { + content: ""; +} + +.read-more-trigger { + cursor: pointer; + display: inline-block; + padding: 0 .5em; + color: #187794; + font-size: .9em; + line-height: 2; + border: 1px solid #ddd; + border-radius: .25em; + font-weight: normal; +} + +.read-more-trigger::after { + content: ""; +} + +.read-more-wrap { + margin-bottom: 2px; +} + +.read-more-wrap::after{ + content: " ..."; + +} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/helpers.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/helpers.py new file mode 100644 index 0000000..28b22df --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/helpers.py @@ -0,0 +1,723 @@ +from multiprocessing import context +import ckan.authz as authz +import ckan.model as model +from webhelpers2.html import literal +from webhelpers2.text import truncate +import ckan.lib.helpers as h +import ckan.logic as logic +from ckan.common import config +from ckanext.d4science_theme.d4sdiscovery.d4s_namespaces_controller import D4S_Namespaces_Controller +from ckanext.d4science_theme.d4sdiscovery.d4s_namespaces_extras_util import D4S_Namespaces_Extra_Util +from ckanext.d4science_theme.qrcodelink.generate_qrcode import D4S_QrCode +import urllib.request, urllib.error, urllib.parse + +from ckan.common import ( + _, g, c, request, session +) + +import random +from operator import itemgetter +from logging import getLogger +import base64 +import sys, os, re +import configparser +import collections +import ckan.plugins.toolkit as tk +import ckan.logic as logic + + +log = getLogger(__name__) + +systemtype_field = 'systemtypefield' +systemtype_field_default_value = 'system:type' +ic_proxy_url_field = 'ic_proxy_url' +ic_proxy_url_field_default_value = "https://registry.d4science.org/icproxy/gcube/service" +application_token_field = 'application_token' +namespaces_generic_resource_id_default_value = "23d827cd-ba8e-4d8c-9ab4-6303bdb7d1db" +namespaces_gr_id_fieldname = "namespaces_generic_resource_id" +namespaceseparator_field = 'namespace_separator' +namespaceseparator_field_default_value = ':' +systemtype_rgb_colors = ['#c0392b ', '#585858', '#04407C', '#9b59b6', '#2ecc71', '#16a085', '#7f8c8d ', '#2ecc71', + '#FA8072', '#00FFFF', '#C76611', '#f39c12', '#800000'] +systemtype_field_colors = 'systemtype_field_colors' + +systemtype_cms_fields_placeholders = {'prefix': 'system:cm_', 'item_status': 'system:cm_item_status'} + +NOCATEOGORY = 'nocategory' +TRANSLATE_OF_ = 'translate_of_' + +ctg_namespace_ctrl = None + +# def get_tag_list() +# return logic.get_action('tag_list') + +# ADDED BY FRANCESCO.MANGIACRAPA, related to Task #5196 +def get_user_role_for_group_or_org(group_id, user_name): + ''' Returns the user's role for the group. (Ignores privileges that cascade + in a group hierarchy.)''' + return authz.users_role_for_group_or_org(group_id, user_name) + + +# ADDED BY FRANCESCO.MANGIACRAPA, related to breadcrumb for Group +def get_parents_for_group(group_name_or_id): + ''' Returns the user's role for the group. (Ignores privileges that cascade + in a group hierarchy.)''' + group = model.Group.get(group_name_or_id) + if group: + return model.Group.get_parent_group_hierarchy(group) + else: + return None + + +# ADDED BY FRANCESCO.MANGIACRAPA +def get_header_param(parameter_name, default=None): + ''' This function allows templates to access header string parameters + from the request. ''' + return request.headers.get(parameter_name, default) + + +# ADDED BY FRANCESCO.MANGIACRAPA +def get_request_param(parameter_name, default=None): + ''' This function allows templates to access query string parameters + from the request. ''' + return request.args.get(parameter_name, default) + + +# ADDED BY FRANCESCO.MANGIACRAPA +def get_cookie_value(cookie_name, default=None): + ''' This function allows templates to access cookie by cookie_name parameter + from the request. ''' + + value = request.cookies.get(cookie_name) + + if value is None: + print(('cookie: ' + cookie_name + ', has value None')) + else: + print(('cookie: ' + cookie_name + ', has value ' + value)) + + return value + + +# Updated BY FRANCESCO.MANGIACRAPA, added allow_html +def markdown_extract_html(text, extract_length=190, allow_html=False): + ''' Returns the plain text representation of markdown encoded text. That + is the texted without any html tags. If extract_length is 0 then it + will not be truncated.''' + if not text: + return '' + if allow_html: + plain = h.markdown(text.strip()) + else: + plain = h.RE_MD_HTML_TAGS.sub('', h.markdown(text)) + + if not extract_length or len(plain) < extract_length: + return literal(plain) + return literal(str(truncate(plain, length=extract_length, indicator='...', whole_word=True))) + + +def get_systemtype_field_dict_from_session(): + '''Return the value of 'ckan.d4science_theme.metadatatypefield' + read from production.ini''' + + systemtype_fieldname = session.get(systemtype_field) + + if systemtype_fieldname is None: + log.info(systemtype_field + " not found in session, loading from config") + else: + log.debug(systemtype_field + " found in session having value: %s" % systemtype_fieldname) + return systemtype_fieldname + + systemtype_fieldname = config.get('ckan.d4science_theme.' + systemtype_field) + + if systemtype_fieldname is None: + log.info( + systemtype_field + " field does not exist in production.ini, returning default value %s" % systemtype_field_default_value) + systemtype_fieldname = systemtype_field_default_value + + separator = get_namespace_separator_from_session() + log.debug("Replacing %s" % separator + " with empty string for key %s" % systemtype_field) + systemtype_fieldname_name = systemtype_fieldname.replace(separator, "") + purgedfieldname = purge_namespace_to_fieldname(systemtype_fieldname) + log.debug("Setting %s" % systemtype_fieldname + " in session for key %s" % systemtype_field) + session[systemtype_field] = {'id': systemtype_fieldname, 'name': systemtype_fieldname_name, + 'title': purgedfieldname} + session.save() + return session[systemtype_field] + + +def get_d4s_namespace_controller(): + '''Instance the D4S_Namespaces_Controller and check that the namespaces are not empty reading it from IS and/or using a Caching system. + The ic-proxy-url is built by reading the configurations from production.ini''' + + d4s_extras_controller = D4S_Namespaces_Controller.getInstance() + global ctg_namespace_ctrl + + if ctg_namespace_ctrl is not None: + log.info("ctg_namespace_ctrl with configurations is NOT None") + the_namespaces = d4s_extras_controller.load_namespaces(ctg_namespace_ctrl['ic_proxy_url'], + ctg_namespace_ctrl['resource_id'], + ctg_namespace_ctrl['application_token']) + log.debug("the_namespaces are %s" % the_namespaces) + + if the_namespaces is None or len(the_namespaces) == 0: + log.info("D4S_Namespaces_Controller obj with none or empty namespaces, going to read them") + else: + log.info("d4s_namespaces_controller found and the namespaces property is not empty: %s" % d4s_extras_controller) + return d4s_extras_controller + else: + log.info("ctg_namespace_ctrl with configurations is None, instancing it") + + ic_proxy_url_value = config.get('ckan.d4science_theme.' + ic_proxy_url_field) + + if ic_proxy_url_value is None: + log.info( + "ckan.d4science_theme." + ic_proxy_url_field + " field does not exist in production.ini, returning default value %s" % ic_proxy_url_field_default_value) + ic_proxy_url_value = ic_proxy_url_field_default_value + + application_token_fieldname = config.get('ckan.d4science_theme.' + application_token_field) + + if application_token_fieldname is None: + log.error("ckan.d4science_theme." + application_token_field + " field does not exist in production.ini!!!") + application_token_fieldname = None + + namespaces_gr_id_fieldname_value = config.get('ckan.d4science_theme.' + namespaces_gr_id_fieldname) + + if namespaces_gr_id_fieldname_value is None: + log.error("ckan.d4science_theme." + application_token_field + " field does not exist in production.ini!!!") + namespaces_gr_id_fieldname_value = namespaces_generic_resource_id_default_value + + # filling the ctg_namespace_ctrl with IS configurations to perform the query for loading the namespaces from IS + ctg_namespace_ctrl = {'ic_proxy_url': ic_proxy_url_value, + 'application_token': application_token_fieldname, + 'resource_id': namespaces_gr_id_fieldname_value} + + d4s_extras_controller.load_namespaces(ctg_namespace_ctrl['ic_proxy_url'], ctg_namespace_ctrl['resource_id'], + ctg_namespace_ctrl['application_token']) + + return d4s_extras_controller + + +def get_extras_indexed_for_namespaces(extras): + namespace_dict = get_namespaces_dict() + # log.info("my_namespace_dict %s" % namespace_dict) + my_extra = get_extras(extras) + # log.info("my_extra is %s" % my_extra) + # d4s_extras_controller = D4S_Namespaces_Controller.getInstance() + # extras_indexed_for_categories = d4s_extras_controller.get_extras_indexed_for_namespaces(namespace_dict, my_extra) + + extras_indexed_for_categories = D4S_Namespaces_Extra_Util().get_extras_indexed_for_namespaces(namespace_dict, + my_extra) + return extras_indexed_for_categories + + +def get_namespaces_dict(): + d4s_extras_controller = get_d4s_namespace_controller() + + if d4s_extras_controller is not None: + return d4s_extras_controller.get_dict_ctg_namespaces() + else: + log.info("local_extras_controller is null, returning empty dictionary for namespaces") + return {} + + +def get_extra_for_category(extras_indexed_for_categories, key_category): + if key_category in extras_indexed_for_categories: + catalogue_namespace = extras_indexed_for_categories[key_category] + return catalogue_namespace.extras + + return [] + + +def get_systemtype_value_from_extras(package, extras=None): + '''Returns the value of metadata fied read from key 'metadatatype' + stored into extra fields if it exists, 'No Type' otherwise''' + systemtype_dict = get_systemtype_field_dict_from_session() + + no_type = 'No Type' + + if extras is None: + return no_type + + for extra in extras: + k, v = extra['key'], extra['value'] + log.debug("key is %s" % k) + log.debug("value is %s" % v) + if k == str(systemtype_dict['id']): + return v + + return no_type + + +def get_namespace_separator_from_session(): + '''Returns the character used to separate namespace from fieldname''' + + separator = session.get(namespaceseparator_field) + + if separator is None: + log.info(namespaceseparator_field + " not found in session, loading from config") + else: + log.debug(namespaceseparator_field + " found in session: %s" % separator) + return separator + + namespace_sep = config.get('ckan.d4science_theme.' + namespaceseparator_field) + + if namespace_sep is None: + log.info( + namespaceseparator_field + " field does not exist in production.ini, returning default value %s" % namespaceseparator_field_default_value) + namespace_sep = namespaceseparator_field_default_value + + log.debug("Setting %s" % namespace_sep + " in session for key %s" % namespaceseparator_field) + session[namespaceseparator_field] = namespace_sep + return namespace_sep + + +def get_extras(package_extras, auto_clean=False, subs=None, exclude=None): + ''' Used for outputting package extras + + :param package_extras: the package extras + :type package_extras: dict + :param auto_clean: If true capitalize and replace -_ with spaces + :type auto_clean: bool + :param subs: substitutes to use instead of given keys + :type subs: dict {'key': 'replacement'} + :param exclude: keys to exclude + :type exclude: list of strings + ''' + + # If exclude is not supplied use values defined in the config + if not exclude: + exclude = g.package_hide_extras + output = [] + for extra in package_extras: + if extra.get('state') == 'deleted': + continue + k, v = extra['key'], extra['value'] + if k in exclude: + continue + if subs and k in subs: + k = subs[k] + elif auto_clean: + k = k.replace('_', ' ').replace('-', ' ').title() + if isinstance(v, (list, tuple)): + v = ", ".join(map(str, v)) + output.append((k, v)) + return output + + +def purge_namespace_to_fieldname(fieldname): + separator = get_namespace_separator_from_session() + + if fieldname is None: + return "" + + if separator not in fieldname: + return fieldname + + end = fieldname.index(separator) + 1 + max_l = len(fieldname) + if end < max_l: + return fieldname[end:max_l] + return fieldname + + +def purge_namespace_to_string(facet): + if not c.search_facets or \ + not c.search_facets.get(facet) or \ + not c.search_facets.get(facet).get('items'): + return "" + + facet_name = c.search_facets.get(facet) + print(("facet_name " + str(facet_name))) + end = str(facet_name).index(":") + if end <= len(facet_name): + return facet_name[:end] + return facet_name + + +def count_facet_items_dict(facet, limit=None, exclude_active=False): + if not c.search_facets or \ + not c.search_facets.get(facet) or \ + not c.search_facets.get(facet).get('items'): + return 0 + facets = [] + for facet_item in c.search_facets.get(facet)['items']: + if not len(facet_item['name'].strip()): + continue + if not (facet, facet_item['name']) in list(request.args.items()): + facets.append(dict(active=False, **facet_item)) + elif not exclude_active: + facets.append(dict(active=True, **facet_item)) + + # for count, + # print "facets " + str(facets) + total = len(facets) + log.debug("total facet: %s" % facet + " are %d" % total) + return total + + +def random_color(): + rgbl = [255, 0, 0] + random.shuffle(rgbl) + return tuple(rgbl) + + +def check_url(the_url): + try: + urllib.request.urlopen(the_url) + return True + except urllib.error.HTTPError as e: + # print(e.code) + return False + except urllib.error.URLError as e: + # print(e.args) + return False + except Exception as error: + # print(error) + return False + + +def get_color_for_type(systemtype_field_value): + '''Return a color assigned to a system type''' + + systemtypecolors = session.get(systemtype_field_colors) + # log.info("color: getting color for type: %s" %systemtype_field_value) + + if systemtypecolors is None: + log.info("color: " + systemtype_field_colors + " not found in session, creating new one") + systemtypecolors = {} + session[systemtype_field_colors] = systemtypecolors + else: + log.debug("color: " + systemtype_field_colors + " found in session having value: %s" % systemtypecolors) + + e_color = systemtypecolors.get(systemtype_field_value) + + if e_color is None: + usedcolorsLen = len(systemtypecolors) + colorsLen = len(systemtype_rgb_colors) + index = usedcolorsLen if usedcolorsLen < colorsLen else random.randint(0, colorsLen - 1) + e_color = systemtype_rgb_colors[index] + # log.debug("color: adding color %s" %e_color +" index is: "+str(index)) + systemtypecolors[systemtype_field_value] = e_color + session[systemtype_field_colors] = systemtypecolors + + session.save() + # log.debug("color: returning color %s" %e_color +" for type: "+systemtype_field_value) + return e_color + + +def ordered_dictionary(list_to_be_sorted, property='name', ordering="asc"): + # print ("dict %s" %list_to_be_sorted) + + ord = False if ordering == "asc" else True + + if list_to_be_sorted: + return sorted(list_to_be_sorted, key=itemgetter(property), reverse=ord) + + return list_to_be_sorted + + +def qrcode_for_url(url): + if url: + try: + qr_code = D4S_QrCode(url) + image_path = qr_code.get_qrcode_path() + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()) + return "" + except Exception as error: + log.error("Error on getting qrcode for url: " + url + "error: %s" % error) + + return "" + + +def get_list_of_organizations(limit=10, sort='packages'): + to_browse_organizations = [] + try: + data = {} + + if sort: + data['sort'] = sort + + data['limit'] = limit + data['all_fields'] = True + ordered_organizations = [] + ordered_organizations = logic.get_action('organization_list')({}, data) + + for organization in ordered_organizations: + try: + to_browse_obj = {} + + if not organization['name']: + continue + + to_browse_obj['name'] = organization['name'] + + if 'package_count' in organization: + to_browse_obj['package_count'] = organization['package_count'] + + if 'display_name' in organization: + to_browse_obj['display_name'] = organization['display_name'] + + image_url = get_url_to_icon_for_ckan_entity(organization['name'], 'organization', False) + + # Using ICON as first option + if image_url: + to_browse_obj['url'] = image_url + # Using object image_url as second one + elif 'image_url' in organization and organization['image_url']: + to_browse_obj['url'] = organization['image_url'] + # Default placeholder + else: + to_browse_obj['url'] = h.url_for_static('/images/organisations/icon/placeholder-organization.png') + + to_browse_organizations.append(to_browse_obj) + except (logic.NotFound, logic.ValidationError, logic.NotAuthorized) as error: + # SILENT + log.warn("Error on putting organization: %s" % error) + + log.info("browse %d" % len(ordered_organizations) + " organisation/s") + except (logic.NotFound, logic.ValidationError, logic.NotAuthorized) as error: + log.error("Error on getting organizations: %s" % error) + return [] + + return to_browse_organizations + + +def get_list_of_groups(limit=10, sort='package_count'): + to_browse_groups = [] + try: + data = {} + if sort: + data['sort'] = sort + + data['limit'] = limit + data['all_fields'] = True + ordered_groups = [] + ordered_groups = logic.get_action('group_list')({}, data) + + log.debug("group_list: "+ ", ".join(ordered_groups)) + + for group in ordered_groups: + # print "\n\ngroup %s" %group + try: + to_browse_obj = {} + + if not group['name']: + continue + + to_browse_obj['name'] = group['name'] + + if 'package_count' in group: + to_browse_obj['package_count'] = group['package_count'] + + if 'display_name' in group: + to_browse_obj['display_name'] = group['display_name'] + + if 'image_url' in group and group['image_url']: + to_browse_obj['url'] = group['image_url'] + else: + to_browse_obj['url'] = get_url_to_icon_for_ckan_entity(group['name'], 'group') + + to_browse_groups.append(to_browse_obj) + except (logic.NotFound, logic.ValidationError, logic.NotAuthorized) as error: + # SILENT + log.warn("Error on putting group: %s" % error) + + log.info("browse %d" % len(ordered_groups) + " organisation/s") + except (logic.NotFound, logic.ValidationError, logic.NotAuthorized) as error: + log.error("Error on getting group: %s" % error) + return [] + + return to_browse_groups + + +def get_browse_info_for_organisations_or_groups(type='organization', limit=10, sort_field=None): + sort = None + if sort_field: + sort = sort_field + + if type == 'organization': + if sort: + return get_list_of_organizations(limit, sort) + else: + return get_list_of_organizations(limit) + + elif type == 'group': + if sort: + return get_list_of_groups(limit, sort) + else: + return get_list_of_groups(limit) + + return [] + + +def get_image_display_for_group(item_id): + if item_id: + try: + item_obj = model.Group.get(item_id) + + if item_obj and item_obj.image_url: + return item_obj.image_url + else: + return h.url_for_static('/images/groups/icon/placeholder-group.png') + + except Exception as error: + log.error("Error on getting item obj: %s" % item_id + "error: %s" % error) + + +def get_application_path(): + if getattr(sys, 'frozen', False): + # If the application is run as a bundle, the pyInstaller bootloader + # extends the sys module by a flag frozen=True and sets the app + # path into variable _MEIPASS'. + application_path = sys._MEIPASS + else: + application_path = os.path.dirname(os.path.abspath(__file__)) + + return application_path + + +''' +Get icon url for input entity type +@:param default_placeholder if True returns the URL of default image, otherwise None. +''' + + +def get_url_to_icon_for_ckan_entity(item_name, entity_type=None, default_placeholder=True): + if not entity_type or not item_name: + return None + + dir_images_full_path = get_application_path() + "/public/images" + dir_images_relative_path = "/images" + + if entity_type == 'group': + dir_images_full_path += "/groups" + dir_images_relative_path += "/groups" + placeholder_icon = "placeholder-group.png" + elif entity_type == 'organization': + dir_images_full_path += "/organisations" + dir_images_relative_path += "/organisations" + placeholder_icon = "placeholder-organization.png" + elif entity_type == 'type': + dir_images_full_path += "/types" + dir_images_relative_path += "/types" + placeholder_icon = "placeholder-type.png" + else: + return None + + icon_path = dir_images_full_path + "/icon/" + item_name.lower() + ".png" + if os.path.isfile(icon_path): + return h.url_for_static(dir_images_relative_path + "/icon/" + item_name.lower() + ".png") + elif default_placeholder: + return h.url_for_static(dir_images_relative_path + "/icon/" + placeholder_icon) + + return None + + +def get_user_info(user_id_or_name): + if user_id_or_name: + try: + + item_obj = model.User.get(user_id_or_name) + + if item_obj: + return item_obj + + return None + except Exception as error: + log.error("Error on getting item obj: %s" % user_id_or_name + "error: %s" % error) + + return None + + +''' +Search the value of my_search_string into input file {ckan_po_file} or the default file ckan.po provided as CKAN language +and returns its translate +''' + + +def get_ckan_translate_for(ckan_po_file, my_search_string): + my_translate = session.get(TRANSLATE_OF_ + my_search_string) + + if not my_search_string: + return "" + + if my_translate: + log.info("Translate of '%s' " % my_search_string + " found in session as: %s" % my_translate) + return my_translate + + if not ckan_po_file: + ckan_po_file = "/usr/lib/ckan/default/src/ckan/ckan/i18n/en_GB/LC_MESSAGES/ckan.po" + + numlines = 0 + numfound = 0 + found = 0 + line_text = "" + + try: + infile = open(ckan_po_file, "r") + + for line in infile: + numlines += 1 + if found > 0: + numfound += 1 + line_text += str(line) + found = 0 # reset found + + # found += line.upper().count(my_search_string.upper()) + found += line.count(my_search_string) + + if found > 0: + log.debug("The search string '%s'" % my_search_string + " was found. Read the line: %s" % str(line)) + + infile.close() + + except Exception as e: + print(("Exception during parsing the file %s" % ckan_po_file, e)) + + log.info("Recap: '%s' was found" % my_search_string + " %i times " % numfound + "in %i lines" % numlines) + log.debug("Line text is: %s" % line_text) + + pattern = '"([A-Za-z0-9_ \./\\-]*)"' + m = re.search(pattern, line_text) + + try: + my_translate = m.group() + except Exception as e: + print(("Pattern %s" % my_search_string + " not found ", e)) + + if my_translate: + log.debug("Replacing quotas...") + my_translate = my_translate.replace("\"", "") + + log.info("Found the string '%s'" % my_translate + " that translating '%s'" % my_search_string) + + session[TRANSLATE_OF_ + my_search_string] = my_translate + session.save() + + return my_translate + + +def get_location_to_bboxes(): + config = configparser.ConfigParser() + config.optionxform = str + location_to_bboxes = {} + try: + bboxes_file = get_application_path() + "/public/location_to_bboxes.ini" + log.debug("bboxes_file is: '%s'" % bboxes_file) + config.read(bboxes_file) + for section_name in config.sections(): + log.debug('Location to bboxes Section: ' + section_name) + # print ' Options:', parser.options(section_name) + for name, value in config.items(section_name): + location_to_bboxes[name] = value.replace(",", "%2C") + + ordDictBboxes = collections.OrderedDict(sorted(location_to_bboxes.items())) + log.debug("Ordered 'bboxes_file' dict: '%s'" % ordDictBboxes) + return ordDictBboxes + except Exception as error: + log.error("Error on reading file: %s" % bboxes_file + "error: %s" % error) + +def get_content_moderator_system_placeholder(): + return systemtype_cms_fields_placeholders + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/plugin.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/plugin.py new file mode 100644 index 0000000..5143a72 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/plugin.py @@ -0,0 +1,470 @@ +# encoding: utf-8 +from logging import getLogger + +import ckan.plugins as plugins +from ckanext.d4science_theme import helpers +import ckan.plugins.toolkit as toolkit +import ckan.lib.dictization.model_save as model_save +import ckan.model as model +import ckan.lib.helpers as h +import sqlalchemy as sa +from ckanext.d4science_theme.controllers.organization import OrganizationVREController +from ckanext.d4science_theme.controllers.home import d4SHomeController +from ckanext.d4science_theme.controllers.systemtype import d4STypeController +from ckanext.d4science_theme.controllers.organization import OrganizationVREController +#from ckan.controllers.home import HomeController +from ckan.config.middleware.common_middleware import TrackingMiddleware +#from ckan.plugins import IRoutes +from flask import Blueprint, render_template + +from ckan.common import ( + g +) +from flask import Flask, g +from ckan.lib.app_globals import app_globals +import ckan.plugins.toolkit as toolkit + + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +log = getLogger(__name__) + +d4s_ctg_namespaces_controller = None + +def remove_check_replicated_custom_key(schema): + if schema is not None: + schema.pop('__before', None) + + return schema + +#CREATED BY FRANCESCO MANGIACRAPA FOR OVERRIDING THE package_extras_save FROM dictization.model_save.py +def _package_extras_save(extra_dicts, obj, context): + ''' It can save repeated extras as key-value ''' + allow_partial_update = context.get("allow_partial_update", False) + if extra_dicts is None and allow_partial_update: + return + + model = context["model"] + session = context["session"] + + #ADDED BY FRANCESCO MANGIACRAPA + log.debug("extra_dicts: "+ str(extra_dicts)) + #print "extra_dicts: "+str(extra_dicts) + + extras_list = obj.extras_list + #extras = dict((extra.key, extra) for extra in extras_list) + old_extras = {} + extras = {} + for extra in extras_list or []: + old_extras.setdefault(extra.key, []).append(extra.value) + extras.setdefault(extra.key, []).append(extra) + + #ADDED BY FRANCESCO MANGIACRAPA + #print "old_extras: "+str(old_extras) + + new_extras = {} + for extra_dict in extra_dicts or []: + #print 'extra_dict key: '+extra_dict["key"] + ', value: '+extra_dict["value"] + #new_extras.setdefault(extra_dict["key"], []).append(extra_dict["value"]) + if extra_dict.get("deleted"): + log.debug("extra_dict deleted: "+str(extra_dict["key"])) + #print 'extra_dict deleted: '+extra_dict["key"] + continue + + #if extra_dict['value'] is not None and not extra_dict["value"] == "": + if extra_dict['value'] is not None: + new_extras.setdefault(extra_dict["key"], []).append(extra_dict["value"]) + + #ADDED BY FRANCESCO MANGIACRAPA + log.debug("new_extras: "+str(new_extras)) + #print "new_extras: "+str(new_extras) + + #new + for key in set(new_extras.keys()) - set(old_extras.keys()): + state = 'active' + log.debug("adding key: "+str(key)) + #print "adding key: "+str(key) + extra_lst = new_extras[key] + for extra in extra_lst: + extra = model.PackageExtra(state=state, key=key, value=extra) + session.add(extra) + extras_list.append(extra) + + #deleted + for key in set(old_extras.keys()) - set(new_extras.keys()): + log.debug("deleting key: "+str(key)) + #print "deleting key: "+str(key) + extra_lst = extras[key] + for extra in extra_lst: + state = 'deleted' + extra.state = state + extras_list.remove(extra) + + #changed + for key in set(new_extras.keys()) & set(old_extras.keys()): + #for each value of new list + for value in new_extras[key]: + old_occur = old_extras[key].count(value) + new_occur = new_extras[key].count(value) + log.debug("value: "+str(value) + ", new_occur: "+str(new_occur)+ ", old_occur: "+str(old_occur)) + #print "value: "+str(value) + ", new_occur: "+str(new_occur) + ", old_occur: "+str(old_occur) + # it is an old value deleted or not + if value in old_extras[key]: + if old_occur == new_occur: + #print "extra - occurrences of: "+str(value) +", are equal into both list" + log.debug("extra - occurrences of: "+str(value) +", are equal into both list") + #there is a little bug, this code return always the first element, so I'm fixing with #FIX-STATUS + extra_values = get_package_for_value(extras[key], value) + #extras_list.append(extra) + for extra in extra_values: + state = 'active' + extra.state = state + session.add(extra) + #print "extra updated: "+str(extra) + log.debug("extra updated: "+str(extra)) + + elif new_occur > old_occur: + #print "extra - a new occurrence of: "+str(value) +", is present into new list, adding it to old list" + log.debug("extra - a new occurrence of: "+str(value) +", is present into new list, adding it to old list") + state = 'active' + extra = model.PackageExtra(state=state, key=key, value=value) + extra.state = state + session.add(extra) + extras_list.append(extra) + old_extras[key].append(value) + log.debug("old extra values updated: "+str(old_extras[key])) + #print "old extra values updated: "+str(old_extras[key]) + + else: + #remove all occurrences deleted - this code could be optimized, it is run several times but could be performed one shot + countDelete = old_occur-new_occur + log.debug("extra - occurrence of: "+str(value) +", is not present into new list, removing "+str(countDelete) + " occurrence/s from old list") + #print "extra - occurrence of: "+str(value) +", is not present into new list, removing "+str(countDelete)+" occurrence/s from old list" + extra_values = get_package_for_value(extras[key], value) + for idx, extra in enumerate(extra_values): + if idx < countDelete: + #print "extra - occurrence of: "+str(value) +", is not present into new list, removing it from old list" + log.debug("pkg extra deleting: "+str(extra.value)) + #print "pkg extra deleting: "+str(extra.value) + state = 'deleted' + extra.state = state + + else: + #print "pkg extra reactivating: "+str(extra.value) + log.debug("pkg extra reactivating: "+str(extra.value)) + state = 'active' + extra.state = state + session.add(extra) + + else: + #print "extra new value: "+str(value) + log.debug("extra new value: "+str(value)) + state = 'active' + extra = model.PackageExtra(state=state, key=key, value=value) + extra.state = state + session.add(extra) + extras_list.append(extra) + + + #for each value of old list + for value in old_extras[key]: + #if value is not present in new list + if value not in new_extras[key]: + extra_values = get_package_for_value(extras[key], value) + for extra in extra_values: + #print "not present extra deleting: "+str(extra) + log.debug("not present extra deleting: "+str(extra)) + state = 'deleted' + extra.state = state + + +#ADDED BY FRANCESCO MANGIACRAPA +def get_package_for_value(list_package, value): + ''' Returns a list of packages containing the value passed in input + ''' + lst = [] + for x in list_package: + if x.value == value: + lst.append(x) + else: + return lst + + return lst + +#OVERRIDING BASE SQL ALCHEMY ENGINE INSTANCE +def _init_TrackingMiddleware(self, app, config): + self.app = app + log.debug('TrackingMiddleware d4Science instance') + sqlalchemy_url = config.get('sqlalchemy.url') + log.debug('sqlalchemy_url read: '+str(sqlalchemy_url)) + + sqlalchemy_pool = config.get('sqlalchemy.pool_size') + if sqlalchemy_pool is None: + sqlalchemy_pool = 5 + + log.debug('sqlalchemy_pool read: '+str(sqlalchemy_pool)) + sqlalchemy_overflow = config.get('sqlalchemy.max_overflow') + + if sqlalchemy_overflow is None: + sqlalchemy_overflow = 10; + + log.debug('sqlalchemy_overflow read: '+str(sqlalchemy_overflow)) + + try: + self.engine = sa.create_engine(sqlalchemy_url, pool_size=int(sqlalchemy_pool), max_overflow=int(sqlalchemy_overflow)) + except TypeError as e: + log.error('pool size does not work: ' +str(e.args)) + self.engine = sa.create_engine(sqlalchemy_url) + + + +class D4Science_ThemePlugin(plugins.SingletonPlugin, toolkit.DefaultDatasetForm): + plugins.implements(plugins.IConfigurer) + plugins.implements(plugins.IDatasetForm) + plugins.implements(plugins.ITemplateHelpers) + plugins.implements(plugins.IFacets) + #plugins.implements(IRoutes, inherit=True) + + #ckan 2.10 + plugins.implements(plugins.IBlueprint) + + # IConfigurer + def update_config(self, config_): + # Add this plugin's templates dir to CKAN's extra_template_paths, so + # that CKAN will use this plugin's custom templates. + toolkit.add_template_directory(config_, 'templates') + + # Add this plugin's public dir to CKAN's extra_public_paths, so + # that CKAN will use this plugin's custom static files. + toolkit.add_public_directory(config_, 'public') + + # Register this plugin's fanstatic directory with CKAN. + # Here, 'fanstatic' is the path to the fanstatic directory + # (relative to this plugin.py file), and 'example_theme' is the name + # that we'll use to refer to this fanstatic directory from CKAN + # templates. + toolkit.add_resource('assets', 'd4science_theme') + # toolkit.add_resource('assets', 'd4science_scripts') + + #IDatasetForm + def create_package_schema(self): + # let's grab the default schema in our plugin + schema = super(D4Science_ThemePlugin, self).create_package_schema() + schema = remove_check_replicated_custom_key(schema) + #d.package_dict_save = _package_dict_save + return schema + + #IDatasetForm + def update_package_schema(self): + schema = super(D4Science_ThemePlugin, self).update_package_schema() + schema = remove_check_replicated_custom_key(schema) + return schema + + #IDatasetForm + def show_package_schema(self): + schema = super(D4Science_ThemePlugin, self).show_package_schema() + schema = remove_check_replicated_custom_key(schema) + return schema + + #IDatasetForm + def is_fallback(self): + # Return True to register this plugin as the default handler for package types not handled by any other IDatasetForm plugin + return False + + #IDatasetForm + def package_types(self): + # This plugin doesn't handle any special package types, it just + # registers itself as the default (above). + return [] + + + #ITemplateHelpers + def get_helpers(self): + log.info("get_helpers called...") + '''Register functions as a template + helper function. + ''' + # Template helper function names should begin with the name of the + # extension they belong to, to avoid clashing with functions from + # other extensions. + return { + 'd4science_theme_get_user_role_for_group_or_org': helpers.get_user_role_for_group_or_org, + 'd4science_theme_get_parents_for_group': helpers.get_parents_for_group, + 'get_header_param': helpers.get_header_param, + 'get_request_param': helpers.get_request_param, + 'get_cookie_value': helpers.get_cookie_value, + 'd4science_theme_markdown_extract_html' : helpers.markdown_extract_html, + 'd4science_theme_get_systemtype_value_from_extras' : helpers.get_systemtype_value_from_extras, + 'd4science_theme_get_systemtype_field_dict_from_session' : helpers.get_systemtype_field_dict_from_session, + 'd4science_theme_get_namespace_separator_from_session' : helpers.get_namespace_separator_from_session, + 'd4science_theme_get_extras' : helpers.get_extras, + 'd4science_theme_count_facet_items_dict' : helpers.count_facet_items_dict, + 'd4science_theme_purge_namespace_to_facet': helpers.purge_namespace_to_fieldname, + 'd4science_get_color_for_type': helpers.get_color_for_type, + 'd4science_get_d4s_namespace_controller': helpers.get_d4s_namespace_controller, + 'd4science_get_extras_indexed_for_namespaces': helpers.get_extras_indexed_for_namespaces, + 'd4science_get_namespaces_dict': helpers.get_namespaces_dict, + 'd4science_get_extra_for_category' : helpers.get_extra_for_category, + 'd4science_get_ordered_dictionary': helpers.ordered_dictionary, + 'd4science_get_qrcode_for_url': helpers.qrcode_for_url, + 'd4science_get_list_of_organizations': helpers.get_list_of_organizations, + 'd4science_get_image_display_for_group': helpers.get_image_display_for_group, + 'd4science_get_list_of_groups': helpers.get_list_of_groups, + 'd4science_get_browse_info_for_organisations_or_groups': helpers.get_browse_info_for_organisations_or_groups, + 'd4science_get_user_info': helpers.get_user_info, + 'd4science_get_url_to_icon_for_ckan_entity' : helpers.get_url_to_icon_for_ckan_entity, + 'd4science_get_ckan_translate_for' : helpers.get_ckan_translate_for, + 'd4science_get_location_to_bboxes' : helpers.get_location_to_bboxes, + 'd4science_get_content_moderator_system_placeholder': helpers.get_content_moderator_system_placeholder, + } + + #Overriding package_extras_save method + model_save.package_extras_save = _package_extras_save + + #Overriding index home controller - rimosso in ckan 2.10 + #d4sHC = d4SHomeController() + # HomeController.index = d4sHC.index + + #OVERRIDING BASE SQL ALCHEMY ENGINE INSTANCE + TrackingMiddleware.__init__ = _init_TrackingMiddleware + + global d4s_ctg_namespaces_controller + + #if d4s_ctg_namespaces_controller is None: + # log.info("d4s_ctg_namespaces_controller instancing...") + # d4s_ctg_namespaces_controller = helpers.get_d4s_namespace_controller() + # log.info("d4s_ctg_namespaces_controller instancied %s" % d4s_ctg_namespaces_controller) + + + #IFacets + def dataset_facets(self, facets_dict, package_type): + facets_dict = self._update_facets(facets_dict) + return facets_dict + + def group_facets(self, facets_dict, group_type, package_type): + # facets_dict = self._update_facets(facets_dict) + return facets_dict + + def organization_facets(self, facets_dict, organization_type, package_type): + # facets_dict = self._update_facets(facets_dict) + return facets_dict + + def _update_facets(self, facets_dict): + '''Add 'metadatatype' to facets if not already present.''' + + log.debug("facets_dict: ") + log.debug(', '.join(facets_dict)) + + metadatatype = helpers.get_systemtype_field_dict_from_session() + + '''Adding system:type''' + facet_title = helpers.purge_namespace_to_fieldname(str(metadatatype['id'])) + facet_title = plugins.toolkit._(facet_title.capitalize() + 's') + facets_dict = self._add_or_update_facet(metadatatype['name'],facet_title, facets_dict) + + log.info("facets dict after update: " + ', '.join(facets_dict)) + log.info("site_url is: " + g.site_url) + + #ADD IT IN THE CUSTOMIZATION? + if g.site_url: + + dev_sites = ['https://ckan-d-d4s.d4science.org'] + #GRSF Catalogues. 'Status of the Record' must be distributed everywhere, see #23398 + grsf_sites = ['https://ckan-grsf-admin2.d4science.org', 'https://ckan-grsf.pre.d4science.org', 'https://ckan-grsf.d4science.org', 'https://ckan-grsf-pre.d4science.org'] + sbd_sites = ['https://ckan.sobigdata.d4science.net', 'https://ckan-sobigdata.d4science.org', + 'https://ckan-sobigdata2.d4science.org'] + + if g.site_url in dev_sites: + '''Adding Status of the GRSF record''' + facets_dict = self._add_or_update_facet("StatusoftheRecord", "Status of the Record", facets_dict, + display_after_facet='groups') + + facets_dict = self._add_or_update_facet("Anno", "Anno", facets_dict, + display_after_facet='groups') + + elif g.site_url in grsf_sites: + '''Adding Status of the GRSF record''' + # facets_dict = self._add_or_update_facet("StatusoftheGRSFrecord", "Status of the GRSF record", facets_dict, display_after_facet='groups') + # Fixing #23348 + facets_dict = self._add_or_update_facet("StatusoftheRecord", "Status of the Record", facets_dict, + display_after_facet='groups') + elif g.site_url in sbd_sites: + '''Adding the field Availability ''' + facets_dict = self._add_or_update_facet("Availability", "Availability", facets_dict, + display_after_facet='groups') + + return facets_dict + + def init_template_globals(app): + from ckan.lib.app_globals import app_globals + app.jinja_env.globals.update(g=app_globals) + + #changed to migrate to ckan 2.10: + def get_blueprint(self): + d4sHC = d4SHomeController() + d4sTC = d4STypeController() + d4sOC = OrganizationVREController() + + blueprint = Blueprint('d4s', self.__module__) + + def tags(): + return render_template('tag/index.html') + + def groups(): + return render_template('group/index.html') + + rules = [ + ('/', 'index', d4sHC.index), + ('/types', 'types', d4sTC.index), + ('/organization_vre', 'organization_vre', d4sOC.index), + ('/tags', 'tags', tags), + ('/groups', 'groups', groups), + ] + for rule in rules: + blueprint.add_url_rule(*rule) + + return blueprint + + # def before_map(self, map): + # """This IRoutes implementation overrides the standard + # ``/user/register`` behaviour with a custom controller. You + # might instead use it to provide a completely new page, for + # example. + # Note that we have also provided a custom register form + # template at ``theme/templates/user/register.html``. + # """ + # # Hook in our custom user controller at the points of creation + # # and edition. + # # + # #map.connect('/type', controller='ckanext.d4science_theme.controllers.type::d4STypeController', action='index') + # map.connect('/type', controller='ckanext.d4science_theme.controllers.systemtype:d4STypeController', action='index') + # ''' Added by Francesco Mangiacrapa, see: #8964 ''' + # organization_vre = OrganizationVREController() + # map.connect('/organization_vre', controller='ckanext.d4science_theme.controllers.organization:OrganizationVREController', action='index') + # map.connect('/organization_vre/{id}', controller='ckanext.d4science_theme.controllers.organization:OrganizationVREController', action='read') + # map.redirect('/types', "/type") + # return map + + + def _add_or_update_facet(self, facet_key, facet_value, facets_dict, display_after_facet='organization'): + + #Updating ordering of facets_dict OrderedDict + if str(facet_key) not in facets_dict: + + new_orderded_facets_dict=facets_dict.__class__() + for key, value in list(facets_dict.items()): + new_orderded_facets_dict[key]=value + # #the field 'metadatatype' will be inserted after following key + if key==display_after_facet: + new_orderded_facets_dict[facet_key]=facet_value + + facets_dict.clear() + facets_dict.update(new_orderded_facets_dict) + log.debug("facets_dict ordered: ") + log.debug(', '.join(facets_dict)) + + return facets_dict + + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/.gitignore b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo.png new file mode 100644 index 0000000..27dce14 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo2.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo2.png new file mode 100644 index 0000000..1c378c5 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo2.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/bg-noise.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/bg-noise.png new file mode 100644 index 0000000..40828c6 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/bg-noise.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/bg-pattern.svg b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/bg-pattern.svg new file mode 100644 index 0000000..0a3e7c8 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/bg-pattern.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/ckan-logo-footer.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/ckan-logo-footer.png new file mode 100644 index 0000000..09aa4ca Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/ckan-logo-footer.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4ScienceDataCatalogue.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4ScienceDataCatalogue.png new file mode 100644 index 0000000..8b7d380 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4ScienceDataCatalogue.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4s_tagcloud.js b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4s_tagcloud.js new file mode 100644 index 0000000..aa3c487 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4s_tagcloud.js @@ -0,0 +1,58 @@ +/*! + * d4s_tagcloud.js + * D4science Tag Cloud which using Tag Cloud Plugin for JQuery + * + * jquery.tagcloud.js + * created by Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it + */ +loadTagCloudJS = function (elementIDtoCloud, rgb_start, rgb_end) { + + //console.log('start: '+rgb_start) + //console.log('end: '+rgb_end) + + if(!rgb_start) + rgb_start = '#C0C0C0'; + + if(!rgb_end) + rgb_end = '#000066'; + + var script = document.createElement('script'); + script.onload = function() { + /*console.log("TagCloud json loaded and ready");*/ + $.fn.tagcloud.defaults = { + size: {start: 13, end: 20, unit: 'px'}, + color: {start: rgb_start, end: rgb_end} + } + $('#'+elementIDtoCloud +' a').tagcloud(); + }; + + script.type = "text/javascript"; + script.src = "jquery.tagcloud.js"; + document.getElementsByTagName('head')[0].appendChild(script); +} + +loadCloud = function (elementIDtoCloud, rgb_start, rgb_end) { + + if(!window.jQuery){ + var script = document.createElement('script'); + script.onload = function() { + /*console.log("JQuery loaded and ready");*/ + loadTagCloudJS(elementIDtoCloud,rgb_start,rgb_end); + }; + + script.type = "text/javascript"; + script.src = "https://code.jquery.com/jquery-1.11.0.min.js"; + document.getElementsByTagName('head')[0].appendChild(script); + + }else { + loadTagCloudJS(elementIDtoCloud,rgb_start,rgb_end); + } + + /*SHUFFLE TAGS*/ + var cloud = document.querySelector('#'+elementIDtoCloud); + if (cloud == null) + return; + for (var i = cloud.children.length; i >= 0; i--) { + cloud.appendChild(cloud.children[Math.random() * i | 0]); + } +} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4science.ico b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4science.ico new file mode 100644 index 0000000..718bf5d Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4science.ico differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4science_logo.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4science_logo.png new file mode 100644 index 0000000..3b87305 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/d4science_logo.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/favicon.ico b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/favicon.ico new file mode 100644 index 0000000..718bf5d Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/favicon.ico differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/gCube_70.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/gCube_70.png new file mode 100644 index 0000000..018d52c Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/gCube_70.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/gcubedatacataloguelogo.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/gcubedatacataloguelogo.png new file mode 100644 index 0000000..1b4bf52 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/gcubedatacataloguelogo.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/grsf/GRSF_for_admins_logo.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/grsf/GRSF_for_admins_logo.png new file mode 100644 index 0000000..dbf83de Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/grsf/GRSF_for_admins_logo.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/groups/icon/placeholder-group.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/groups/icon/placeholder-group.png new file mode 100644 index 0000000..1ece150 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/groups/icon/placeholder-group.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/d4sciencelabs.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/d4sciencelabs.png new file mode 100644 index 0000000..7d1a75e Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/d4sciencelabs.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/emodnet.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/emodnet.png new file mode 100644 index 0000000..0724a33 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/emodnet.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/fao.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/fao.png new file mode 100644 index 0000000..13d5ef0 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/fao.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/grsf.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/grsf.png new file mode 100644 index 0000000..91ccbbb Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/grsf.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/d4sciencelabs.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/d4sciencelabs.png new file mode 100644 index 0000000..e0b8d80 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/d4sciencelabs.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/emodnet.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/emodnet.png new file mode 100644 index 0000000..4eb8091 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/emodnet.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/fao.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/fao.png new file mode 100644 index 0000000..aa815b4 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/fao.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/grsf.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/grsf.png new file mode 100644 index 0000000..4343813 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/grsf.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/imarine.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/imarine.png new file mode 100644 index 0000000..9d7a311 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/imarine.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/placeholder-organization.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/placeholder-organization.png new file mode 100644 index 0000000..30616f2 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/placeholder-organization.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/rprototypinglab.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/rprototypinglab.png new file mode 100644 index 0000000..743f19c Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/icon/rprototypinglab.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/imarine.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/imarine.png new file mode 100644 index 0000000..875348a Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/imarine.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/rprototypinglab.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/rprototypinglab.png new file mode 100644 index 0000000..472294b Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/organisations/rprototypinglab.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/codelist.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/codelist.png new file mode 100644 index 0000000..5cb017a Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/codelist.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/dataset.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/dataset.png new file mode 100644 index 0000000..8ded500 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/dataset.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/dsd.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/dsd.png new file mode 100644 index 0000000..101975b Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/dsd.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/metadata.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/metadata.png new file mode 100644 index 0000000..84d395e Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/metadata.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/placeholder-type.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/placeholder-type.png new file mode 100644 index 0000000..1ca5afb Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/placeholder-type.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/researchobject.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/researchobject.png new file mode 100644 index 0000000..cab2b45 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/researchobject.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/series.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/series.png new file mode 100644 index 0000000..573d43f Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/series.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/service.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/service.png new file mode 100644 index 0000000..54dd849 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/service.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/trainingmaterial.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/trainingmaterial.png new file mode 100644 index 0000000..38ea713 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/trainingmaterial.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/virtualresearchenvironment.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/virtualresearchenvironment.png new file mode 100644 index 0000000..91a8a97 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/icon/virtualresearchenvironment.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/placeholder-type.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/placeholder-type.png new file mode 100644 index 0000000..d09e87e Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/images/types/placeholder-type.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/jquery.tagcloud.js b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/jquery.tagcloud.js new file mode 100644 index 0000000..4e5d5a3 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/jquery.tagcloud.js @@ -0,0 +1,92 @@ +/*! + * jquery.tagcloud.js + * A Simple Tag Cloud Plugin for JQuery + * + * https://github.com/addywaddy/jquery.tagcloud.js + * created by Adam Groves + */ +(function($) { + + /*global jQuery*/ + "use strict"; + + var compareWeights = function(a, b) + { + return a - b; + }; + + // Converts hex to an RGB array + var toRGB = function(code) { + if (code.length === 4) { + code = code.replace(/(\w)(\w)(\w)/gi, "\$1\$1\$2\$2\$3\$3"); + } + var hex = /(\w{2})(\w{2})(\w{2})/.exec(code); + return [parseInt(hex[1], 16), parseInt(hex[2], 16), parseInt(hex[3], 16)]; + }; + + // Converts an RGB array to hex + var toHex = function(ary) { + return "#" + jQuery.map(ary, function(i) { + var hex = i.toString(16); + hex = (hex.length === 1) ? "0" + hex : hex; + return hex; + }).join(""); + }; + + var colorIncrement = function(color, range) { + return jQuery.map(toRGB(color.end), function(n, i) { + return (n - toRGB(color.start)[i])/range; + }); + }; + + var tagColor = function(color, increment, weighting) { + var rgb = jQuery.map(toRGB(color.start), function(n, i) { + var ref = Math.round(n + (increment[i] * weighting)); + if (ref > 255) { + ref = 255; + } else { + if (ref < 0) { + ref = 0; + } + } + return ref; + }); + return toHex(rgb); + }; + + $.fn.tagcloud = function(options) { + + var opts = $.extend({}, $.fn.tagcloud.defaults, options); + var tagWeights = this.map(function(){ + return $(this).attr("rel"); + }); + tagWeights = jQuery.makeArray(tagWeights).sort(compareWeights); + var lowest = tagWeights[0]; + var highest = tagWeights.pop(); + var range = highest - lowest; + if(range === 0) {range = 1;} + // Sizes + var fontIncr, colorIncr; + if (opts.size) { + fontIncr = (opts.size.end - opts.size.start)/range; + } + // Colors + if (opts.color) { + colorIncr = colorIncrement (opts.color, range); + } + return this.each(function() { + var weighting = $(this).attr("rel") - lowest; + if (opts.size) { + $(this).css({"font-size": opts.size.start + (weighting * fontIncr) + opts.size.unit}); + } + if (opts.color) { + $(this).css({"color": tagColor(opts.color, colorIncr, weighting)}); + } + }); + }; + + $.fn.tagcloud.defaults = { + size: {start: 14, end: 18, unit: "pt"} + }; + +})(jQuery); diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/location_to_bboxes.ini b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/location_to_bboxes.ini new file mode 100644 index 0000000..e7f14c2 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/location_to_bboxes.ini @@ -0,0 +1,16 @@ +[location_to_bboxes_epsg_4326] +Antarctica=-180,-90,180,-63.2706604895 +Brazil=-73.9872354804,-33.7683777809,-34.7299934555,5.24448639569 +France=-54.5247541978,2.05338918702,9.56001631027,51.1485061713 +Greece=20.1500159034,34.9199876979,26.6041955909,41.8269046087 +Italy=6.7499552751,36.619987291,18.4802470232,47.1153931748 +Ivory Coast=-8.60288021487,4.33828847902,-2.56218950033,10.5240607772 +Mexico=-117.12776,14.5388286402,-86.811982388,32.72083 +Nigeria=2.69170169436,4.24059418377,14.5771777686,13.8659239771 +Philippines=117.17427453,5.58100332277,126.537423944,18.5052273625 +Portugal=-9.52657060387,36.838268541,-6.3890876937,42.280468655 +Puerto Rico=-67.2424275377,17.946553453,-65.5910037909,18.5206011011 +Slovenia=13.6981099789,45.4523163926,16.5648083839,46.8523859727 +Thailand=97.3758964376,5.69138418215,105.589038527,20.4178496363 +United Kingdom=-7.57216793459,49.959999905,1.68153079591,58.6350001085 +United States=-171.791110603,18.91619,-66.96466,71.3577635769 \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/oai2_style.xsl b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/oai2_style.xsl new file mode 100644 index 0000000..2a41373 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/oai2_style.xsl @@ -0,0 +1,690 @@ + + + + + + + + + + + + + + + +td.value { + vertical-align: top; + padding-left: 1em; + padding: 3px; +} +td.key { + background-color: #e0e0ff; + padding: 3px; + text-align: right; + border: 1px solid #c0c0c0; + white-space: nowrap; + font-weight: bold; + vertical-align: top; +} +.dcdata td.key { + background-color: #ffffe0; +} +body { + margin: 1em 2em 1em 2em; +} +h1, h2, h3 { + font-family: sans-serif; + clear: left; +} +h1 { + padding-bottom: 2px; + margin-bottom: 0px; +} +h2 { + margin-bottom: 0.5em; +} +h3 { + margin-bottom: 0.3em; + font-size: medium; +} + +h5 { + color: gray; + font-size: 12px; + margin: 0; + padding-top: 5px; +} + +.about-xsl { + font-size: 12px; + font-family: "Arial"; + color: gray; +} + +.link { + border: 1px outset #88f; + background-color: #c0c0ff; + padding: 1px 4px 1px 4px; + font-size: 80%; + text-decoration: none; + font-weight: bold; + font-family: sans-serif; + color: black; +} +.link:hover { + color: red; +} +.link:active { + color: red; + border: 1px inset #88f; + background-color: #a0a0df; +} +.oaiRecord, .oaiRecordTitle { + background-color: #f0f0ff; + border-style: solid; + border-color: #d0d0d0; +} +h2.oaiRecordTitle { + background-color: #e0e0ff; + font-size: medium; + font-weight: bold; + padding: 10px; + border-width: 2px 2px 0px 2px; + margin: 0px; +} +.oaiRecord { + margin-bottom: 3em; + border-width: 2px; + padding: 10px; +} + +.results { + margin-bottom: 1.5em; +} +ul.quicklinks { + margin-top: 3px; + padding: 4px; + text-align: left; + border-bottom: 1px solid #ccc; + border-top: 1px solid #ccc; + clear: left; + list-style-type: none; +} +ul.quicklinks li { + font-size: 80%; + #display: inline; + list-stlye: none; + font-family: sans-serif; + padding-left: 12px; +} + +.oai-footer{ + border-top: 1px solid #ccc; +} + +p.intro { + font-size: 12px; + font-family: "Arial"; + color: gray; +} + + + + + + + + + OAI 2.0 Request Results + + + +

OAI 2.0 Request Results

+

You are viewing an HTML version of the XML OAI response. More information about this XSLT.
Return to OAI-PMH 2.0 Home for this Repository

+ + + + + +
+ + +
OAI-PMH Requests:
+ +
+ + + + + + + + + + + + + + +
Datestamp of response
Request URL
+ + + +

OAI Error(s)

+

The request could not be completed due to the following error or errors.

+
+ +
+
+ +

Request was of type:

+
+ + + + + + +
+
+
+
+ + + + + + + + +
Error Code
+

+
+ + + + + + + + + + + + + + + + + + +
Repository Name
Base URL
Protocol Version
Earliest Datestamp
Deleted Record Policy
Granularity
+ + +
+ + + Admin Email + + + + + + +

Unsupported Description Type

+

The XSL currently does not support this type of description.

+
+ +
+
+ + + + + +

OAI-Identifier

+ + + + + + + + + +
Scheme
Repository Identifier
Delimiter
Sample OAI Identifier
+
+ + + + + +

EPrints Description

+

Content

+ + +

Submission Policy

+ +
+

Metadata Policy

+ +

Data Policy

+ + +

Content

+ +
+ +
+ + + +

+
+ +
+
+
+ + +

Comment

+
+
+ + + + + +

Friends

+
    + +
+
+ + +
  • + +Identify
  • +
    + + + + + +

    Branding

    + + +
    + + +

    Icon

    + + + {br:title} + + + {br:title} + + +
    + + +

    Metadata Rendering Rule

    + + + + + + + +
    URL
    Namespace
    Mime Type
    +
    + + + + + + +

    Gateway Information

    + + + + + + + + + + + + + + +
    Source
    Description
    URL
    Notes
    +
    + + + Admin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Set

    + + + + +
    setName
    +
    + + + + + + +

    This is a list of metadata formats available for the record "". Use these links to view the metadata:

    +
    + +

    This is a list of metadata formats available from this archive.

    +
    +
    + +
    + + +

    Metadata Format

    + + + + + + + +
    metadataPrefix
    metadataNamespace
    schema
    +
    + + + + + + + + +

    OAI Record:

    +
    + + + +
    +
    + + +

    OAI Record Header

    + + + + + + +
    OAI Identifier + + oai_dc + rdf +
    Datestamp
    + +

    This record has been deleted.

    +
    +
    + + + +

    "about" part of record container not supported by the XSL

    +
    + + +   + + + + + + + + + + setSpec + + Identifiers + Records + + + + + + + + +

    There are more results.

    + + + +
    resumptionToken: + +Resume
    +
    + + + + +

    Unknown Metadata Format

    +
    + +
    +
    + + + + +
    +

    Dublin Core Metadata (oai_dc)

    + + +
    +
    +
    + + +Title + + +Author or Creator + + +Subject and Keywords + + +Description + + +Publisher + + +Other Contributor + + +Date + + +Resource Type + + +Format + + +Resource Identifier + + +Source + + +Language + + +Relation + + + + + URL + URL not shown as it is very long. + + + + + + + + + + + + + +Coverage + + +Rights Management + + + + +
    + <></> +
    +
    + + + + + ="" + + + +.xmlSource { + font-size: 70%; + border: solid #c0c0a0 1px; + background-color: #ffffe0; + padding: 2em 2em 2em 0em; +} +.xmlBlock { + padding-left: 2em; +} +.xmlTagName { + color: #800000; + font-weight: bold; +} +.xmlAttrName { + font-weight: bold; +} +.xmlAttrValue { + color: #0000c0; +} + + +
    + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/pageloading.gif b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/pageloading.gif new file mode 100644 index 0000000..ea92a4c Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/pageloading.gif differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/parthenos/logo-parthenos.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/parthenos/logo-parthenos.png new file mode 100644 index 0000000..7fd8e9b Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/parthenos/logo-parthenos.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/placeholder_types.png b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/placeholder_types.png new file mode 100644 index 0000000..cc33636 Binary files /dev/null and b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/public/placeholder_types.png differ diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/qrcodelink/__init__.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/qrcodelink/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/qrcodelink/generate_qrcode.py b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/qrcodelink/generate_qrcode.py new file mode 100644 index 0000000..1909226 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/qrcodelink/generate_qrcode.py @@ -0,0 +1,80 @@ +import os +import tempfile +import logging +import pyqrcode +import time + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +CATALINA_HOME = 'CATALINA_HOME' +log = logging.getLogger(__name__) + +temp_dir = None +qr_code_dir = None +qr_code_dir_name = "qr_code_for_catalogue" + + +class D4S_QrCode(): + def __init__(self, qr_code_url=None): + self._qr_code_url = qr_code_url + global temp_dir + if temp_dir is None: + D4S_QrCode.init_temp_dir() + if temp_dir is None: + raise Exception('No temp directory found!') + + def get_qrcode_path(self): + image_name = self._qr_code_url.rsplit('/', 1)[-1] + image_name+=".svg" + image_path = os.path.join(qr_code_dir, image_name) + # ONLY IF QRCODE DOES NOT EXIST THEN IT WILL BE CREATED + if not os.path.isfile(image_path): + url = pyqrcode.create(self._qr_code_url) + url.svg(image_path, scale=3) + log.debug("Created QRCode image: " + image_name) + + attempt = 0 + while not os.path.exists(image_path) and attempt < 3: + time.sleep(1) + attempt += 1 + + if os.path.isfile(image_path): + log.info("QRcode image exists at: " + image_path) + else: + log.error("%s isn't a file!" % image_path) + + return image_path + + @classmethod + def init_temp_dir(cls): + global temp_dir + global qr_code_dir_name + global qr_code_dir + try: + temp_dir = str(os.environ[CATALINA_HOME]) + temp_dir = os.path.join(temp_dir, "temp") + except KeyError as error: + log.error("No environment variable for: %s" % CATALINA_HOME) + + if temp_dir is None: + temp_dir = tempfile.gettempdir() # using system tmp dir + + log.debug("Temp dir is: %s" % temp_dir) + + qr_code_dir = os.path.join(temp_dir, qr_code_dir_name) + + if not os.path.exists(qr_code_dir): + os.makedirs(qr_code_dir) + + def get_temp_directory(self): + return temp_dir + + def get_qr_code_dir(self): + return qr_code_dir + + +# D4S_QrCode.init_temp_dir() +#qr_code = D4S_QrCode("http://data.d4science.org/ctlg/BiodiversityLab/distribution_of_the_giant_squid_architeuthis") +#print qr_code.get_qrcode_path() diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/activity_streams/activity_stream_email_notifications.text b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/activity_streams/activity_stream_email_notifications.text new file mode 100644 index 0000000..505710b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/activity_streams/activity_stream_email_notifications.text @@ -0,0 +1,7 @@ +{% set num = activities|length %}{{ ngettext("You have {num} new activity on your {site_title} dashboard", "You have {num} new activities on your {site_title} dashboard", num).format(site_title=g.site_title if g else site_title, num=num) }} {{ _('To view your dashboard, click on this link:') }} + +{% url_for 'dashboard.index', _external=True %} + +{{ _('You can turn off these email notifications in your {site_title} preferences. To change your preferences, click on this link:').format(site_title=g.site_title if g else site_title) }} + +{% url_for 'user.edit', _external=True %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/base.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/base.html new file mode 100644 index 0000000..806d8c9 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/base.html @@ -0,0 +1,12 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ _('Administration') }}{% endblock %} + +{% block breadcrumb_content %}{% endblock %} + +{% block content_primary_nav %} + {{ h.build_nav_icon('admin.index', _('Sysadmins'), icon='gavel') }} + {{ h.build_nav_icon('admin.config', _('Config'), icon='gear') }} + {{ h.build_nav_icon('admin.trash', _('Trash'), icon='trash') }} + {{ h.build_extra_admin_nav() }} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/config.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/config.html new file mode 100644 index 0000000..0c29625 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/config.html @@ -0,0 +1,72 @@ +{% import 'macros/autoform.html' as autoform %} + +{% extends "admin/base.html" %} + +{% import 'macros/form.html' as form %} + +{% block primary_content_inner %} + + {{ form.errors(error_summary) }} + +
    + {% block admin_form %} + {{ h.csrf_input() }} + + {{ form.input('ckan.site_title', id='field-ckan-site-title', label=_('Site Title'), value=data['ckan.site_title'], error=error, classes=['control-medium']) }} + + {{ form.input('ckan.theme', id='field-ckan-main-css', label=_('Custom Stylesheet'), value=data['ckan.theme'], error=error, classes=['control-medium']) }} + + {{ form.input('ckan.site_description', id='field-ckan-site-description', label=_('Site Tag Line'), value=data['ckan.site_description'], error=error, classes=['control-medium']) }} + + {% set field_url = 'ckan.site_logo' %} + {% set is_upload = data[field_url] and not data[field_url].startswith('http') %} + {% set is_url = data[field_url] and data[field_url].startswith('http') %} + {{ form.image_upload(data, errors, is_upload_enabled=h.uploads_enabled(), is_url=is_url, is_upload=is_upload, upload_label = _('Site logo'), url_label=_('Site logo'), field_url=field_url, field_upload='logo_upload', field_clear='clear_logo_upload' )}} + + {{ form.markdown('ckan.site_about', id='field-ckan-site-about', label=_('About'), value=data['ckan.site_about'], error=error, placeholder=_('About page text')) }} + + {{ form.markdown('ckan.site_intro_text', id='field-ckan-site-intro-text', label=_('Intro Text'), value=data['ckan.site_intro_text'], error=error, placeholder=_('Text on home page')) }} + + {{ form.textarea('ckan.site_custom_css', id='field-ckan-site-custom-css', label=_('Custom CSS'), value=data['ckan.site_custom_css'], error=error, placeholder=_('Customisable css inserted into the page header')) }} + + {{ form.select('ckan.homepage_style', id='field-homepage-style', label=_('Homepage'), options=homepages, selected=data['ckan.homepage_style'], error=error) }} + {% endblock %} +
    + {{ _('Reset') }} + +
    +
    +{% endblock %} + +{% block secondary_content %} +
    +

    + + {{ _('CKAN config options') }} +

    +
    + {% block admin_form_help %} + {% set about_url = h.url_for('home.about') %} + {% set home_url = h.url_for('home.index') %} + {% set docs_url = "http://docs.ckan.org/en/{0}/theming".format(g.ckan_doc_version) %} + {% trans %} +

    Site Title: This is the title of this CKAN instance + It appears in various places throughout CKAN.

    +

    Custom Stylesheet: Define an alternative main CSS file.

    +

    Site Tag Logo: This is the logo that appears in the + header of all the CKAN instance templates.

    +

    About: This text will appear on this CKAN instances + about page.

    +

    Intro Text: This text will appear on this CKAN instances + home page as a welcome to visitors.

    +

    Custom CSS: This is a block of CSS that appears in + <head> tag of every page. If you wish to customize + the templates more fully we recommend + reading the documentation.

    +

    Homepage: This is for choosing a predefined layout for + the modules that appear on your homepage.

    + {% endtrans %} + {% endblock %} +
    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/confirm_reset.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/confirm_reset.html new file mode 100644 index 0000000..3e5a716 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/confirm_reset.html @@ -0,0 +1,14 @@ +{% extends "admin/base.html" %} + +{% block subtitle %}{{ _("Confirm Reset") }}{% endblock %} + +{% block primary_content_inner %} +
    + {{ h.csrf_input() }} +

    {{ _('Are you sure you want to reset the config?') }}

    +

    + + +

    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/index.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/index.html new file mode 100644 index 0000000..d6e7439 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/index.html @@ -0,0 +1,84 @@ +{% extends "admin/base.html" %} + +{% block primary_content_inner %} +

    {{ _('Current Sysadmins') }}

    + + + + + + + + + + {% for user in sysadmins %} + + + + + {% endfor %} + +
    {{ _('User') }} 
    {{ h.linked_user(user) }} +
    +
    + {{ h.csrf_input() }} + + + +
    +
    +
    + +
    + +

    {{ _('Promote user to Sysadmin') }}

    + +
    + {{ h.csrf_input() }} +
    +
    + +
    + + +
    + +
    + +
    + +
    +
    +
    +{% endblock %} + +{% block secondary_content %} +
    +

    + + {{ _('Administer CKAN') }} +

    +
    + + {% set docs_url = "http://docs.ckan.org/en/{0}/sysadmin-guide.html".format(g.ckan_doc_version) %} + {% trans %} +

    As a sysadmin user you have full control over this CKAN instance. Proceed with care!

    +

    For guidance on using sysadmin features, see the CKAN sysadmin guide

    + {% endtrans %} +
    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/snippets/confirm_delete.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/snippets/confirm_delete.html new file mode 100644 index 0000000..d4f0a0d --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/snippets/confirm_delete.html @@ -0,0 +1,24 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ _("Confirm Delete") }}{% endblock %} + +{% block maintag %}
    {% endblock %} + +{% block main_content %} +
    +
    + {% block form %} +

    + {{ _(messages.confirm[ent_type]) }} +

    +

    +

    + {{ h.csrf_input() }} + + +
    +

    + {% endblock %} +
    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/snippets/data_type.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/snippets/data_type.html new file mode 100644 index 0000000..c328439 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/snippets/data_type.html @@ -0,0 +1,57 @@ +
    +
    +

    + +

    + +{# entities list can be of different types #} +{% set items = [] %} + + +
    +
      + {% for entity in entities %} + {% set title = entity.title or entity.name %} + {% do items.append(title) %} +
    • + + {{ title|truncate(80) }} + +
    • + {% else %} +

      + {{ _(messages.empty[ent_type]) }} +

      + {% endfor %} +
    + + + {% if items|length > 0 %} +
    + {{ h.csrf_input() }} + + + {{ _('Purge') }} + +
    + {% endif %} +
    +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/trash.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/trash.html new file mode 100644 index 0000000..f3331a6 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/admin/trash.html @@ -0,0 +1,38 @@ +{% extends "admin/base.html" %} + +{% block primary_content_inner %} +
    + {{ h.csrf_input() }} + +
    + +{% for ent_type, entities in data.items() %} + {% snippet "admin/snippets/data_type.html", ent_type=ent_type, entities=entities, messages=messages %} +{% endfor %} +{% endblock %} + +{% block secondary_content %} +
    +

    + + {{ _("Trash") }} +

    +
    +

    + {% trans %} + Purge deleted datasets, organizations or groups forever and irreversibly. + {% endtrans %} +

    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/ajax_snippets/custom_fields.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/ajax_snippets/custom_fields.html new file mode 100644 index 0000000..90f7344 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/ajax_snippets/custom_fields.html @@ -0,0 +1,4 @@ +{# Snippet for unit testing custom-fields.js #} +
    + {% snippet 'snippets/custom_form_fields.html', extras=[{'key': 'key', 'value': 'value'}], errors={} %} +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/ajax_snippets/follow_button.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/ajax_snippets/follow_button.html new file mode 100644 index 0000000..9dc09c9 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/ajax_snippets/follow_button.html @@ -0,0 +1 @@ +{{ h.follow_button(type, id) }} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/base.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/base.html new file mode 100644 index 0000000..192d8e3 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/base.html @@ -0,0 +1,130 @@ +{# Allows the DOCTYPE to be set on a page by page basis #} +{%- block doctype %}{% endblock -%} + +{# Allows custom attributes to be added to the tag #} +{%- block htmltag -%} +{% set lang = h.lang() %} + + +{%- endblock -%} + + {# Allows custom attributes to be added to the tag #} + + {# + Add custom meta tags to the page. Call super() to get the default tags + such as charset, viewport and generator. + + Example: + + {% block meta %} + {{ super() }} + + {% endblock %} + + #} + {%- block meta -%} + + + + + {% block meta_generator %}{% endblock %} + {% block meta_viewport %}{% endblock %} + {%- endblock -%} + + {# + Add a custom title to the page by extending the title block. Call super() + to get the default page title. + + Example: + + {% block title %}My Subtitle - {{ super() }}{% endblock %} + + #} + + {%- block title -%} + {%- block subtitle %}{% endblock -%} + {%- if self.subtitle()|trim %} {{ g.template_title_delimiter }} {% endif -%} + {{ g.site_title }} + {%- endblock -%} + + + {# + The links block allows you to add additonal content before the stylesheets + such as rss feeds and favicons in the same way as the meta block. + #} + {% block links -%} + + {% endblock -%} + + {# + The styles block allows you to add additonal stylesheets to the page in + the same way as the meta block. Use super() to include the default + stylesheets before or after your own. + + Example: + + {% block styles %} + {{ super() }} + + {% endblock %} + #} + {%- block styles %} + {# TODO: store just name of asset instead of path to it. #} + {% set theme = h.get_rtl_theme() if h.is_rtl_language() else g.theme %} + {% asset theme %} + {% asset 'd4science_theme/d4science-js' %} + {% asset 'd4science_theme/d4science-css' %} + {% endblock %} + + {% block head_extras %} + {# defined in the config.ini under "ckan.template_head_end" #} + {{ g.template_head_end | safe }} + {% endblock %} + + {# render all assets included in styles block #} + {{ h.render_assets('style') }} + {%- block custom_styles %} + {%- if g.site_custom_css -%} + + {%- endif %} + {% endblock %} + + + {# Allows custom attributes to be added to the tag #} + + + {# + The page block allows you to add content to the page. Most of the time it is + recommended that you extend one of the page.html templates in order to get + the site header and footer. If you need a clean page then this is the + block to use. + + Example: + + {% block page %} +
    Some other page content
    + {% endblock %} + #} + {%- block page %}{% endblock -%} + + {# + DO NOT USE THIS BLOCK FOR ADDING SCRIPTS + Scripts should be loaded by the {% assets %} tag except in very special + circumstances + #} + {%- block scripts %} + {% endblock -%} + + {% block body_extras -%} + {# defined in the config.ini under "ckan.template_footer_end" #} + {{ g.template_footer_end | safe }} + {%- endblock %} + + {# render all assets included in scripts block and everywhere else #} + {# make sure there are no calls to `asset` tag after this point #} + {{ h.render_assets('style') }} + {{ h.render_assets('script') }} + + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/dataviewer/base.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/dataviewer/base.html new file mode 100644 index 0000000..9f3d714 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/dataviewer/base.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block subtitle %}{{ h.dataset_display_name(package) }} {{ g.template_title_delimiter }} {{h.resource_display_name(resource) }}{% endblock %} + +{# remove any scripts #} +{% block scripts %} + +{% endblock %} + +{# remove any ckan styles #} +{% block styles %}{% endblock %} + +{% block custom_styles %}{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/primer.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/primer.html new file mode 100644 index 0000000..fe4ddc8 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/primer.html @@ -0,0 +1,100 @@ +{% extends "page.html" %} + +{% block toolbar %} +{% snippet 'development/snippets/breadcrumb.html', stage=1 %} +{% snippet 'development/snippets/breadcrumb.html', stage=2 %} +{% snippet 'development/snippets/breadcrumb.html', stage=3 %} +{% endblock %} + +{% block actions_content %} +{% snippet 'development/snippets/actions.html' %} +{% endblock %} + +{% block secondary_content %} +{% snippet 'development/snippets/context.html' %} + +
    +

    Helper text

    +
    {{ lipsum(1) }}
    +
    + +{% snippet 'development/snippets/nav.html', heading='Navigation' %} +{% snippet 'development/snippets/nav.html', heading='Active Navigation', show_active=true %} +{% snippet 'development/snippets/nav.html', heading='Icon Navigation', show_icons=true %} +{% snippet 'development/snippets/facet.html', heading='Facet List', show_icons=true %} +{% endblock %} + +{% block primary_content %} +{% snippet 'development/snippets/page_header.html' %} + +
    +
    + + + + +
    +
    + +
    +

    Top level heading (h1)

    +

    Some Rendered Markdown (h2)

    +
    +

    Heading 1

    + {{ lipsum(1) }} +

    Heading 2

    + {{ lipsum(1) }} +

    Heading 3

    + {{ lipsum(1) }} +
    +
    + +
    +
    +

    Forms

    +
    +{% snippet 'development/snippets/form.html' %} +{% snippet 'development/snippets/form.html', error=['This field has an error'] %} + +
    +
    +

    Form stages

    +
    +{% snippet 'development/snippets/form_stages.html' %} + + +
    +

    Datasets

    +
    + {% snippet 'snippets/package_list.html', packages=[ + {'name': "test", 'title': 'Dataset #1', 'type': 'dataset', 'notes': lipsum(1), 'tracking_summary':{'recent': 10}}, + {'name': "test", 'title': 'Dataset #2', 'type': 'dataset', 'notes': lipsum(0), 'tracking_summary':{'recent': 5}}, + {'name': "test", 'title': 'Dataset #3', 'type': 'dataset', 'notes': lipsum(1), 'tracking_summary':{'recent': 10}}, + {'name': "test", 'title': 'Dataset #4', 'type': 'dataset', 'notes': lipsum(1), 'tracking_summary':{'recent': 10}} + ] %} +
    + +
    +
    +

    Media Grid

    +
    +{% snippet 'development/snippets/media_grid.html', groups=[ +{'name': "test", 'display_name': 'Group #1', 'type': 'group', 'description': lipsum(0), 'packages': 0}, +{'name': "test", 'display_name': 'Group #2', 'type': 'group', 'description': lipsum(1), 'packages': 1}, +{'name': "test", 'display_name': 'Group #3', 'type': 'group', 'description': lipsum(1), 'packages': 10}, +{'name': "test", 'display_name': 'Group #4', 'type': 'group', 'description': lipsum(1), 'packages': 200}, +{'name': "test", 'display_name': 'Group #5', 'type': 'group', 'description': lipsum(1), 'packages': 10}, +{'name': "test", 'display_name': 'Group #6', 'type': 'group', 'description': lipsum(0), 'packages': 5} +] %} + +
    +

    Pagination

    +
    +{% snippet 'development/snippets/pagination.html', total=5, current=1 %} +{% snippet 'development/snippets/pagination.html', total=5, current=3 %} +{% snippet 'development/snippets/pagination.html', total=5, current=5 %} + +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/actions.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/actions.html new file mode 100644 index 0000000..fe9519c --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/actions.html @@ -0,0 +1,2 @@ +
  • Button
  • +
  • Primary Button
  • diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/breadcrumb.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/breadcrumb.html new file mode 100644 index 0000000..9a1e371 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/breadcrumb.html @@ -0,0 +1,7 @@ +
    + +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/context.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/context.html new file mode 100644 index 0000000..936d928 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/context.html @@ -0,0 +1,26 @@ +
    +
    +
    + + + +
    +

    {{ title }}

    +

    + {{ h.markdown_extract(lipsum(1), 160) }} +

    +

    + read more +

    +
    +
    +
    Stat #1
    +
    {{ h.SI_number_span(11111) }}
    +
    +
    +
    Stat #2
    +
    {{ h.SI_number_span(111) }}
    +
    +
    +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/facet.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/facet.html new file mode 100644 index 0000000..9f872cd --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/facet.html @@ -0,0 +1,15 @@ +
    + {% with items=(("First", true), ("Second", false), ("Third", true), ("Fourth", false), ("Last", false)) %} +

    Facet List

    + + + {% endwith %} +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/form.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/form.html new file mode 100644 index 0000000..800fa0b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/form.html @@ -0,0 +1,27 @@ +{% import 'macros/form.html' as form %} + +
    +
    + {{ form.input('standard', label=_('Standard'), placeholder=_('Standard Input'), value='', error=error, classes=[]) }} + {{ form.input('standard', label=_('Medium'), placeholder=_('Medium Width Input'), value='', error=error, classes=['control-medium']) }} + {{ form.input('standard', label=_('Full'), placeholder=_('Full Width Input'), value='', error=error, classes=['control-full']) }} + {{ form.input('standard', label=_('Large'), placeholder=_('Large Input'), value='', error=error, classes=['control-full', 'control-large']) }} + {{ form.prepend('slug', label=_('Prepend'), prepend='prefix', placeholder=_('Prepend Input'), value='', error=error, classes=[]) }} + {{ form.custom( + names=('custom_key', 'custom_value', 'custom_deleted'), + id='field-custom', + label=_('Custom Field (empty)'), + values=(), + error=error ) }} + {{ form.custom( + names=('custom_key', 'custom_value', 'custom_deleted'), + id='field-custom', + label=_('Custom Field'), + values=('key', 'value', true), + error=error ) }} + {{ form.markdown('desc', id='field-description', label=_('Markdown'), placeholder='Some nice placeholder text', error=error) }} + {{ form.textarea('desc', id='field-description', label=_('Textarea'), placeholder='Some nice placeholder text', error=error) }} + {{ form.select('year', label=_('Select'), options=[{'value': 2010}, {'value': 2011}], selected=2011, error=error) }} + {{ form.checkbox('remember', label="This is my checkbox", checked=true, error=error) }} +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/form_stages.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/form_stages.html new file mode 100644 index 0000000..409f0f5 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/form_stages.html @@ -0,0 +1,30 @@ +
    +
    + {% snippet 'package/snippets/stages.html', stages=['active'] %} +
    +
    +
    +
    + {% snippet 'package/snippets/stages.html', stages=['complete', 'active'] %} +
    +
    +
    +
    + {% snippet 'package/snippets/stages.html', stages=['complete', 'complete', 'active'] %} +
    +
    +
    +
    + {% snippet 'package/snippets/stages.html', stages=['complete', 'active', 'complete'] %} +
    +
    +
    +
    + {% snippet 'package/snippets/stages.html', stages=['active', 'complete', 'complete'] %} +
    +
    +
    +
    + {% snippet 'package/snippets/stages.html', stages=['active', 'complete'] %} +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/list.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/list.html new file mode 100644 index 0000000..48dbd87 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/list.html @@ -0,0 +1,14 @@ +
    + {% with items=(("First", false), ("Second", true), ("Third", true), ("Fourth", false), ("Last", false)) %} +

    {{ heading }}

    + + {% endwith %} +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/media_grid.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/media_grid.html new file mode 100644 index 0000000..0ef561f --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/media_grid.html @@ -0,0 +1,5 @@ +
    +
    + {% snippet 'group/snippets/group_list.html', groups=groups %} +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/module.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/module.html new file mode 100644 index 0000000..bc9c8e1 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/module.html @@ -0,0 +1,21 @@ +{% with classes = classes or [], hn = heading_level or 1 %} +
    + {% if heading_link %} + {{ heading }} + {% elif heading_action %} + {{ heading }} + {% elif heading_icon %} + {{ heading }} + {% else %} + {{ heading }} + {% endif %} +
    + {{ lipsum(1) }} +
    + {% if footer %} + + {% endif %} +
    +{% endwith %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/nav.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/nav.html new file mode 100644 index 0000000..da5d917 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/nav.html @@ -0,0 +1,14 @@ +
    + {% with items=(("First", true), ("Second", false), ("Third", true), ("Fourth", false), ("Last", false)) %} +

    {{ heading }}

    + + {% endwith %} +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/page_header.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/page_header.html new file mode 100644 index 0000000..cfc49c9 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/page_header.html @@ -0,0 +1,11 @@ +{% with items=(("First", true), ("Second", false), ("Third", false)) %} + +{% endwith %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/pagination.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/pagination.html new file mode 100644 index 0000000..1a375f0 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/pagination.html @@ -0,0 +1,11 @@ +
    +
    +
      + {% if current != 1 %}
    • «
    • {% endif %} + {% for index in range(1, total+1) %} + {{ index }} + {% endfor %} + {% if current != total %}
    • »
    • {% endif %} +
    +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/simple-input.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/simple-input.html new file mode 100644 index 0000000..00d4d25 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/development/snippets/simple-input.html @@ -0,0 +1,4 @@ +
    +

    Module Narrow Input

    +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/invite_user.txt b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/invite_user.txt new file mode 100644 index 0000000..d9deffe --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/invite_user.txt @@ -0,0 +1,19 @@ +{% trans %} +Dear {{ user_name }}, + +You have been invited to {{ site_title }}. + +A user has already been created for you with the username {{ user_name }}. You can change it later. + +You have been added to the {{ group_type }} {{ group_title }} with the following role: {{ role_name }}. + +To accept this invite, please reset your password at: + + {{ reset_link }} + + +Have a nice day. + +-- +Message sent by {{ site_title }} ({{ site_url }}) +{% endtrans %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/invite_user_subject.txt b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/invite_user_subject.txt new file mode 100644 index 0000000..1e992c1 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/invite_user_subject.txt @@ -0,0 +1,3 @@ +{% trans %} +Invite for {{ site_title }} +{% endtrans %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/reset_password.txt b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/reset_password.txt new file mode 100644 index 0000000..19936fa --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/reset_password.txt @@ -0,0 +1,14 @@ +{% trans %} +Dear {{ user_name }}, + +You have requested your password on {{ site_title }} to be reset. + +Please click the following link to confirm this request: + + {{ reset_link }} + +Have a nice day. + +-- +Message sent by {{ site_title }} ({{ site_url }}) +{% endtrans %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/reset_password_subject.txt b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/reset_password_subject.txt new file mode 100644 index 0000000..4a8941c --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/emails/reset_password_subject.txt @@ -0,0 +1,3 @@ +{% trans %} +Reset your password - {{ site_title }} +{% endtrans %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/error_document_template.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/error_document_template.html new file mode 100644 index 0000000..51acb19 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/error_document_template.html @@ -0,0 +1,31 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ gettext('Error %(error_code)s', error_code=code) }}{% endblock %} + +{% block primary %} +
    +
    + {% if name %} +

    {{ code }} {{ name }}

    + {% endif %} + {{ content}} +
    + {% block login_redirect %} + {% if show_login_redirect_link %} +
    + {{ _("You might need to login to access this page.") }} {{ _("Click here to login") }} +
    + {% endif %} + {% endblock %} +
    +{% endblock %} + +{% block breadcrumb %} +{% endblock %} + +{% block flash %} + {# eat the flash messages caused by the 404 #} + {% set flash_messages = h.get_flashed_messages() %} +{% endblock %} + +{% block secondary %}{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/footer.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/footer.html new file mode 100644 index 0000000..f149c21 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/footer.html @@ -0,0 +1,20 @@ +{% block header_hide_container_content %} +{% set hideParameter = h.get_request_param('hh', None) %} +{% set hide = h.get_cookie_value('ckan_hide_header') %} +
    +{% if hide=='true' %} +{# Updated and unified the footer, see #18126 #} +
    +gCube Catalogue powered by CKAN + |  +Access this catalogue using the gCat APIs +
    +{% else %} +
    +gCube Catalogue powered by CKAN + |  +Access this catalogue using the gCat APIs +
    +{% endif %} +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/about.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/about.html new file mode 100644 index 0000000..07461cf --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/about.html @@ -0,0 +1,16 @@ +{% extends "group/read_base.html" %} + +{% block subtitle %}{{ _('About') }} {{ g.template_title_delimiter }} {{ super() }}{% endblock %} + +{% block primary_content_inner %} +

    {% block page_heading %}{{ group_dict.display_name }}{% endblock %}

    + {% block group_description %} + {% if group_dict.description %} + {{ h.render_markdown(group_dict.description) }} + {% endif %} + {% endblock %} + + {% block group_extras %} + {% snippet 'snippets/additional_info.html', extras = h.sorted_extras(group_dict.extras) %} + {% endblock %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/admins.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/admins.html new file mode 100644 index 0000000..ee98a8a --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/admins.html @@ -0,0 +1,10 @@ +{% extends "group/read_base.html" %} + +{% block subtitle %}{{ _('Administrators') }} {{ g.template_title_delimiter }} {{ group_dict.title or group_dict.name }}{% endblock %} + +{% block primary_content_inner %} +

    {% block page_heading %}{{ _('Administrators') }}{% endblock %}

    + {% block admins_list %} + {% snippet "user/snippets/followers.html", followers=admins %} + {% endblock %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/base_form_page.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/base_form_page.html new file mode 100644 index 0000000..5dea2ef --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/base_form_page.html @@ -0,0 +1,13 @@ +{% extends "group/edit_base.html" %} + + +{% block primary_content_inner %} +

    + {% block page_heading %} + {{ h.humanize_entity_type('group', group_type, 'form label') or _('Group Form'), }} + {% endblock %} +

    + {% block form %} + {{ form | safe }} + {% endblock %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/confirm_delete.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/confirm_delete.html new file mode 100644 index 0000000..8c4b2e6 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/confirm_delete.html @@ -0,0 +1,22 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ _("Confirm Delete") }}{% endblock %} + +{% block maintag %}
    {% endblock %} + +{% block main_content %} +
    +
    + {% block form %} +

    {{ _('Are you sure you want to delete group - {name}?').format(name=group_dict.name) }}

    +

    +

    + {{ h.csrf_input() }} + + +
    +

    + {% endblock %} +
    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/confirm_delete_member.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/confirm_delete_member.html new file mode 100644 index 0000000..4f31781 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/confirm_delete_member.html @@ -0,0 +1,23 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ _("Confirm Delete") }}{% endblock %} + +{% block maintag %}
    {% endblock %} + +{% block main_content %} +
    +
    + {% block form %} +

    {{ _('Are you sure you want to delete member - {name}?').format(name=user_dict.name) }}

    +

    +

    + {{ h.csrf_input() }} + + + +
    +

    + {% endblock %} +
    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/edit.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/edit.html new file mode 100644 index 0000000..31dcd29 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/edit.html @@ -0,0 +1,12 @@ +{% extends "group/base_form_page.html" %} + +{% block breadcrumb_content %} +
  • {% link_for h.humanize_entity_type('group', group_type, 'breadcrumb') or _('Groups'), named_route=group_type+'.index' %}
  • + {% block breadcrumb_content_inner %} +
  • {% link_for group.display_name|truncate(35), named_route=group_type+'.read', id=group.name, title=group.display_name %}
  • +
  • {% link_for _('Manage'), named_route=group_type+'.edit', id=group.name %}
  • + {% endblock %} +{% endblock %} + +{% block page_heading_class %}hide-heading{% endblock %} +{% block page_heading %}{{ h.humanize_entity_type('group', group_type, 'edit label') or _('Edit Group') }}{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/edit_base.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/edit_base.html new file mode 100644 index 0000000..ec92493 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/edit_base.html @@ -0,0 +1,19 @@ +{% extends "page.html" %} +{% set dataset_type = h.default_package_type() %} + +{% block subtitle %}{{ _('Manage') }} {{ g.template_title_delimiter }} {{ group_dict.display_name }} {{ g.template_title_delimiter }} {{ h.humanize_entity_type('group', group_type, 'page title') or _('Groups') }}{% endblock %} + +{% set group = group_dict %} + +{% block content_action %} + {% link_for _('View'), named_route=group_type+'.read', id=group_dict.name, class_='btn btn-default', icon='eye' %} +{% endblock %} + +{% block content_primary_nav %} + {{ h.build_nav_icon(group_type + '.edit', _('Edit'), id=group_dict.name, icon='pencil-square') }} + {{ h.build_nav_icon(group_type + '.members', _('Members'), id=group_dict.name, icon='users') }} +{% endblock %} + +{% block secondary_content %} + {% snippet "group/snippets/info.html", group=group_dict, show_nums=false %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/followers.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/followers.html new file mode 100644 index 0000000..c51255c --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/followers.html @@ -0,0 +1,10 @@ +{% extends "group/read_base.html" %} + +{% block subtitle %}{{ _('Followers') }} {{ g.template_title_delimiter }} {{ group_dict.title or group_dict.name }}{% endblock %} + +{% block primary_content_inner %} +

    {% block page_heading %}{{ _('Followers') }}{% endblock %}

    + {% block followers_list %} + {% snippet "user/snippets/followers.html", followers=followers %} + {% endblock %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/index.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/index.html new file mode 100644 index 0000000..1501bc8 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/index.html @@ -0,0 +1,44 @@ +{% extends "page.html" %} + + +{% block subtitle %}{{ h.humanize_entity_type('group', group_type, 'page title') or _('Groups') }}{% endblock %} + +{% block breadcrumb_content %} +
  • {% link_for h.humanize_entity_type('group', group_type, 'breadcrumb') or _('Groups'), named_route=group_type+'.index' %}
  • +{% endblock %} + +{% block page_header %}{% endblock %} + +{% block page_primary_action %} + {% if h.check_access('group_create') %} + {% link_for h.humanize_entity_type('group', group_type, 'add link') or _('Add Group'), named_route=group_type+'.new', class_='btn btn-primary', icon='plus-square' %} + {% endif %} +{% endblock %} + +{% block primary_content_inner %} +

    {{ h.humanize_entity_type('group', group_type, 'page title') or _('Groups') }}

    + {% block groups_search_form %} + {% snippet 'snippets/search_form.html', form_id='group-search-form', type=group_type, query=q, sorting_selected=sort_by_selected, count=page.item_count, placeholder=h.humanize_entity_type('group', group_type, 'search placeholder') or _('Search groups...'), show_empty=request.args, no_bottom_border=true if page.items, sorting = [(_('Name Ascending'), 'title asc'), (_('Name Descending'), 'title desc')] %} + {% endblock %} + {% block groups_list %} + {% if page.items or request.args %} + {% if page.items %} + {% snippet "group/snippets/group_list.html", groups=page.items %} + {% endif %} + {% else %} +

    + {{ h.humanize_entity_type('group', group_type, 'no any objects') or _('There are currently no groups for this site') }}. + {% if h.check_access('group_create') %} + {% link_for _('How about creating one?'), named_route=group_type+'.new' %}. + {% endif %} +

    + {% endif %} + {% endblock %} + {% block page_pagination %} + {{ page.pager(q=q or '', sort=sort_by_selected or '') }} + {% endblock %} +{% endblock %} + +{% block secondary_content %} + {% snippet "group/snippets/helper.html", group_type=group_type %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/member_new.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/member_new.html new file mode 100644 index 0000000..3234f71 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/member_new.html @@ -0,0 +1,101 @@ +{% extends "group/edit_base.html" %} + +{% import 'macros/form.html' as form %} + +{% set user = user_dict %} + +{% block primary_content_inner %} + {% link_for _('Back to all members'), named_route=group_type+'.members', id=group.name, class_='btn btn-default pull-right', icon='arrow-left' %} +

    + {% block page_heading %}{{ _('Edit Member') if user else _('Add Member') }}{% endblock %} +

    + {% block form %} +
    + {{ h.csrf_input() }} +
    +
    +
    + {% if not user %} + +

    + {{ _('If you wish to add an existing user, search for their username below.') }} +

    + {% endif %} +
    + {% if user %} + + + {% else %} + + {% endif %} +
    +
    +
    + {% if not user %} +
    +
    + {{ _('or') }} +
    +
    +
    +
    + +

    + {{ _('If you wish to invite a new user, enter their email address.') }} +

    +
    + +
    +
    +
    + {% endif %} +
    + + {% if user and user.name == c.user and user_role == 'admin' %} + {% set format_attrs = {'data-module': 'autocomplete', 'disabled': 'disabled'} %} + {{ form.select('role', label=_('Role'), options=roles, selected=user_role, error='', attrs=format_attrs) }} + {{ form.hidden('role', value=user_role) }} + {% else %} + {% set format_attrs = {'data-module': 'autocomplete'} %} + {{ form.select('role', label=_('Role'), options=roles, selected=user_role, error='', attrs=format_attrs) }} + {% endif %} + +
    + {% if user %} + {{ _('Delete') }} + + {% else %} + + {% endif %} +
    +
    + {% endblock %} +{% endblock %} + +{% block secondary_content %} + {{ super() }} +
    +

    + + {{ _('What are roles?') }} +

    +
    + {% trans %} +

    Admin: Can edit group information, as well as + manage organization members.

    +

    Member: Can add/remove datasets from groups

    + {% endtrans %} +
    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/members.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/members.html new file mode 100644 index 0000000..31d09ef --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/members.html @@ -0,0 +1,38 @@ +{% extends "group/edit_base.html" %} + +{% block subtitle %}{{ _('Members') }} {{ g.template_title_delimiter }} {{ group_dict.display_name }} {{ g.template_title_delimiter }} {{ h.humanize_entity_type('group', group_type, 'page title') or _('Groups') }}{% endblock %} + +{% block page_primary_action %} + {% link_for _('Add Member'), named_route=group_type+'.member_new', id=group_dict.id, class_='btn btn-primary', icon='plus-square' %} +{% endblock %} + +{% block primary_content_inner %} +

    {{ _('{0} members'.format(members|length)) }}

    + + + + + + + + + + {% for user_id, user, role in members %} + + + + + + {% endfor %} + +
    {{ _('User') }}{{ _('Role') }}
    + {{ h.linked_user(user_id, maxlength=20) }} + {{ role }} + +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/new.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/new.html new file mode 100644 index 0000000..69230a3 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/new.html @@ -0,0 +1,25 @@ +{% extends "group/base_form_page.html" %} + +{% set label = h.humanize_entity_type('group', group_type, 'create title') or _('Create a Group') %} + + +{% block subtitle %}{{ label }}{% endblock %} + +{% block page_heading %}{{ label }}{% endblock %} + +{% block breadcrumb_content %} +
  • {{ h.nav_link( + h.humanize_entity_type('group', group_type, 'breadcrumb') or _('Groups'), + named_route=group_type+'.index') }}
  • +
  • + {{ h.nav_link( + label, + named_route=group_type~'.new') }} +
  • +{% endblock %} + +{% block page_header %}{% endblock %} + +{% block secondary_content %} + {% snippet "group/snippets/helper.html", group_type=group_type %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/new_group_form.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/new_group_form.html new file mode 100644 index 0000000..7fb4ccd --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/new_group_form.html @@ -0,0 +1,25 @@ +{% extends "group/snippets/group_form.html" %} + +{# + As the form is rendered as a seperate page we take advantage of this by + overriding the form blocks depending on the current context + #} +{% block dataset_fields %} + {% if action == "edit" %}{{ super() }}{% endif %} +{% endblock %} + +{% block custom_fields %} + {% if action == "edit" %}{{ super() }}{% endif %} +{% endblock %} + +{% block save_text %} + {%- if action == "edit" -%} + {{ h.humanize_entity_type('group', group_type, 'update label') or _('Update Group') }} + {%- else -%} + {{ h.humanize_entity_type('group', group_type, 'create label') or _('Create Group') }} + {%- endif -%} +{% endblock %} + +{% block delete_button %} + {% if action == "edit" %}{{ super() }}{% endif %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/read.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/read.html new file mode 100644 index 0000000..ff69aa7 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/read.html @@ -0,0 +1,42 @@ +{% extends "group/read_base.html" %} +{% set dataset_type = h.default_package_type() %} + +{% block primary_content_inner %} + {% block groups_search_form %} + {% set facets = { + 'fields': fields_grouped, + 'search': search_facets, + 'titles': facet_titles, + 'translated_fields': translated_fields, + 'remove_field': remove_field } + %} + {% set sorting = [ + (_('Relevance'), 'score desc, metadata_modified desc'), + (_('Name Ascending'), 'title_string asc'), + (_('Name Descending'), 'title_string desc'), + (_('Last Modified'), 'metadata_modified desc'), + (_('Popular'), 'views_recent desc') if g.tracking_enabled else (false, false) ] + %} + {% snippet 'snippets/search_form.html', form_id='group-datasets-search-form', type=dataset_type, query=q, sorting=sorting, sorting_selected=sort_by_selected, count=page.item_count, facets=facets, placeholder=h.humanize_entity_type('package', dataset_type, 'search placeholder') or _('Search datasets...'), show_empty=request.args, fields=fields %} + {% endblock %} + {% block packages_list %} + {% if page.items %} + {{ h.snippet('snippets/package_list.html', packages=page.items) }} + {% endif %} + {% endblock %} + {% block page_pagination %} + {{ page.pager(q=q) }} + {% endblock %} +{% endblock %} + +{% block secondary_content %} + {{ super() }} +
    +
    + {% for facet in facet_titles %} + {{ h.snippet('snippets/facet_list.html', title=facet_titles[facet], name=facet, extras={'id':group_dict.id}, search_facets=search_facets) }} + {% endfor %} +
    + close +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/read_base.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/read_base.html new file mode 100644 index 0000000..75c869b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/read_base.html @@ -0,0 +1,29 @@ +{% extends "page.html" %} +{% set dataset_type = h.default_package_type() %} + +{% block subtitle %}{{ group_dict.display_name }} {{ g.template_title_delimiter }} {{ h.humanize_entity_type('group', group_type, 'page title') or _('Groups') }}{% endblock %} + +{% block breadcrumb_content %} +
  • {% link_for h.humanize_entity_type('group', group_type, 'breadcrumb') or _('Groups'), named_route=group_type+'.index' %}
  • +
  • {% link_for group_dict.display_name|truncate(35), named_route=group_type+'.read', id=group_dict.name, title=group_dict.display_name %}
  • +{% endblock %} + +{% block content_action %} + {% if h.check_access('group_update', {'id': group_dict.id}) %} + {% link_for _('Manage'), named_route=group_type+'.edit', id=group_dict.name, class_='btn btn-default', icon='wrench' %} + {% endif %} +{% endblock %} + +{% block content_primary_nav %} + {{ h.build_nav_icon(group_type + '.read', h.humanize_entity_type('package', dataset_type, 'content tab') or _('Datasets'), id=group_dict.name, icon='sitemap') }} + {{ h.build_nav_icon(group_type + '.about', _('About'), id=group_dict.name, icon='info-circle') }} +{% endblock %} + +{% block secondary_content %} + {% snippet "group/snippets/info.html", group=group_dict, show_nums=true %} +{% endblock %} + +{% block links %} + {{ super() }} + {% include "group/snippets/feeds.html" %} +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/feeds.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/feeds.html new file mode 100644 index 0000000..26de3a6 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/feeds.html @@ -0,0 +1,2 @@ +{%- set dataset_feed = h.url_for('feeds.group', id=group_dict.name) -%} + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_form.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_form.html new file mode 100644 index 0000000..2e752b5 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_form.html @@ -0,0 +1,45 @@ +{% import 'macros/form.html' as form %} + + +
    + {{ h.csrf_input() }} + {% block error_summary %} + {{ form.errors(error_summary) }} + {% endblock %} + + {% block basic_fields %} + {% set attrs = {'data-module': 'slug-preview-target', 'class': 'form-control'} %} + {{ form.input('title', label=_('Name'), id='field-name', placeholder=h.humanize_entity_type('group', group_type, 'name placeholder') or _('My Group'), value=data.title, error=errors.title, classes=['control-full'], attrs=attrs) }} + + {# Perhaps these should be moved into the controller? #} + {% set prefix = h.url_for(group_type + '.read', id='') %} + {% set domain = h.url_for(group_type + '.read', id='', qualified=true) %} + {% set domain = domain|replace("http://", "")|replace("https://", "") %} + {% set attrs = {'data-module': 'slug-preview-slug', 'class': 'form-control input-sm', 'data-module-prefix': domain, 'data-module-placeholder': '<' + group_type + '>'} %} + + {{ form.prepend('name', label=_('URL'), prepend=prefix, id='field-url', placeholder=_('my-' + group_type), value=data.name, error=errors.name, attrs=attrs, is_required=true) }} + + {{ form.markdown('description', label=_('Description'), id='field-description', placeholder=h.humanize_entity_type('group', group_type, 'description placeholder') or _('A little information about my group...'), value=data.description, error=errors.description) }} + + {% set is_upload = data.image_url and not data.image_url.startswith('http') %} + {% set is_url = data.image_url and data.image_url.startswith('http') %} + + {{ form.image_upload(data, errors, is_upload_enabled=h.uploads_enabled(), is_url=is_url, is_upload=is_upload) }} + + {% endblock %} + + {% block custom_fields %} + {% snippet 'snippets/custom_form_fields.html', extras=data.extras, errors=errors, limit=3 %} + {% endblock %} + + {{ form.required_message() }} + +
    + {% block delete_button %} + {% if h.check_access('group_delete', {'id': data.id}) %} + {% block delete_button_text %}{{ _('Delete') }}{% endblock %} + {% endif %} + {% endblock %} + +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_item.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_item.html new file mode 100644 index 0000000..1908ca6 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_item.html @@ -0,0 +1,50 @@ +{# +Renders a media item for a group. This should be used in a list. + +group - A group dict. + +Example: + +
      + {% for group in groups %} + {% snippet "group/snippets/group_item.html", group=group %} + {% endfor %} +
    +#} +{% set type = group.type or 'group' %} +{% set url = h.url_for(type ~ '.read', id=group.name) %} +{% block item %} +
  • + {% block item_inner %} + {% block image %} + {{ group.name }} + {% endblock %} + {% block title %} +

    {{ group.display_name }}

    + {% endblock %} + {% block description %} + {% if group.description %} +

    {{ h.markdown_extract(group.description, extract_length=80) }}

    + {% endif %} + {% endblock %} + {% block datasets %} + {% if group.package_count %} + {{ ungettext('{num} Dataset', '{num} Datasets', group.package_count).format(num=group.package_count) }} + {% elif group.package_count == 0 %} + {{ _('0 Datasets') }} + {% endif %} + {% endblock %} + {% block link %} + + {{ _('View {name}').format(name=group.display_name) }} + + {% endblock %} + {% if group.user_member %} + + {% endif %} + {% endblock %} +
  • +{% endblock %} +{% if position is divisibleby 3 %} +
  • +{% endif %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_list.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_list.html new file mode 100644 index 0000000..d171296 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/group_list.html @@ -0,0 +1,19 @@ +{# +Display a grid of group items. + +groups - A list of groups. + +Example: + + {% snippet "group/snippets/group_list.html" %} + +#} +{% block group_list %} +
      + {% block group_list_inner %} + {% for group in groups %} + {% snippet "group/snippets/group_item.html", group=group, position=loop.index %} + {% endfor %} + {% endblock %} +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/helper.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/helper.html new file mode 100644 index 0000000..7061646 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/helper.html @@ -0,0 +1,27 @@ +{# + Displays a sidebard module with information about group. + + group_type - The type of group. + + Example: + + {% snippet "group/snippets/helper.html", group_type=group_type %} + + #} + +
    +

    + + {{ _('What are Groups?') }} +

    +
    +

    + {% trans %} + You can use CKAN Groups to create and manage collections of datasets. + This could be to catalogue datasets for a particular project or team, + or on a particular theme, or as a very simple way to help people find + and search your own published datasets. + {% endtrans %} +

    +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/info.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/info.html new file mode 100644 index 0000000..5916124 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/group/snippets/info.html @@ -0,0 +1,54 @@ +{% set dataset_type = h.default_package_type() %} + +{% block info %} +
    +
    + {% block inner %} + {% block image %} +
    + + {{ group.name }} + +
    + {% endblock %} + {% block heading %} +

    + {{ group.display_name }} + {% if group.state == 'deleted' %} + [{{ _('Deleted') }}] + {% endif %} +

    + {% endblock %} + {% block description %} + {% if group.description %} +

    + {{ h.markdown_extract(group.description, 180) }} +

    +

    + {% link_for _('read more'), named_route='group.about', id=group.name %} +

    + {% endif %} + {% endblock %} + {% if show_nums %} + {% block nums %} +
    +
    +
    {{ _('Followers') }}
    +
    {{ h.SI_number_span(group.num_followers) }}
    +
    +
    +
    {{ h.humanize_entity_type('package', dataset_type, 'facet label') or _('Datasets') }}
    +
    {{ h.SI_number_span(group.package_count) }}
    +
    +
    + {% endblock %} + {% block follow %} + + {% endblock %} + {% endif %} + {% endblock %} +
    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/header.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/header.html new file mode 100644 index 0000000..b3b1f17 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/header.html @@ -0,0 +1,123 @@ +{% set dataset_type = h.default_package_type() %} + +{% block header_wrapper %} {% block header_account %} + +{% endblock %} +
    +
    + {% block header_debug %} {% if g.debug and not g.debug_supress_header %} +
    Blueprint : {{ g.blueprint }}
    View : {{ g.view }}
    + {% endif %} {% endblock %} + +
    +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/about.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/about.html new file mode 100644 index 0000000..8ed25d8 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/about.html @@ -0,0 +1,24 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ _('About') }}{% endblock %} + +{% block breadcrumb_content %} +
  • {% link_for _('About'), named_route='home.about' %}
  • +{% endblock %} + +{% block primary %} +
    +
    + {% block about %} + {% if g.site_about %} + {{ h.render_markdown(g.site_about) }} + {% else %} +

    {{ _('About') }}

    + {% snippet 'home/snippets/about_text.html' %} + {% endif %} + {% endblock %} +
    +
    +{% endblock %} + +{% block secondary %}{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/index.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/index.html new file mode 100644 index 0000000..c14d4e0 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/index.html @@ -0,0 +1,18 @@ +{% extends "page.html" %} +{% set homepage_style = ( g.homepage_style or '1' ) %} + +{% block subtitle %}{{ _("Welcome") }}{% endblock %} + +{% block maintag %}{% endblock %} +{% block toolbar %}{% endblock %} + +{% block content %} +
    +
    + {{ self.flash() }} +
    + {% block primary_content %} + {% snippet "home/layout{0}.html".format(homepage_style), search_facets=search_facets %} + {% endblock %} +
    +{% endblock %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/layout1.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/layout1.html new file mode 100644 index 0000000..840f03a --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/layout1.html @@ -0,0 +1,106 @@ + + + + +
    +
    +
    + {% block promoted %} + {% snippet 'home/snippets/promoted.html' %} + {% endblock %} +
    +
    +
    + +
    +
    +
    +
    + {% block search %} + {% snippet 'home/snippets/search.html' %} + {% endblock %} +
    +
    + {% block stats %} + {% snippet 'home/snippets/stats.html' %} + {% endblock %} +
    +
    +
    +
    + + + + + +{% block search_for_organizations %} +{# Added by Francesco Mangiacrapa, see: #8964 #} + + + {% snippet 'home/snippets/search_for_organisations.html' %} +{% endblock %} + +{% block search_for_groups %} + {% snippet 'home/snippets/search_for_groups.html' %} +{% endblock %} + +{% block search_for_types %} + {% snippet 'home/snippets/search_for_types.html' %} +{% endblock %} + + +{# + {% block search_for_location %} + {% snippet 'home/snippets/search_for_location.html' %} + {% endblock %} + +#} + + + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/robots.txt b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/robots.txt new file mode 100644 index 0000000..ca60362 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/robots.txt @@ -0,0 +1,12 @@ +User-agent: * +{% block all_user_agents -%} +Disallow: /dataset/rate/ +Disallow: /revision/ +Disallow: /dataset/*/history +Disallow: /api/ +Crawl-Delay: 10 +{%- endblock %} + +{% block additional_user_agents -%} +{%- endblock %} + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/about_text.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/about_text.html new file mode 100644 index 0000000..21deb89 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/about_text.html @@ -0,0 +1,20 @@ +{% trans %} +

    CKAN is the world’s leading open-source data portal platform.

    + +

    CKAN is a complete out-of-the-box software solution that makes data +accessible and usable – by providing tools to streamline publishing, sharing, +finding and using data (including storage of data and provision of robust data +APIs). CKAN is aimed at data publishers (national and regional governments, +companies and organizations) wanting to make their data open and available.

    + +

    CKAN is used by governments and user groups worldwide and powers a variety +of official and community data portals including portals for local, national +and international government, such as the UK’s data.gov.uk and the +United States catalog.data.gov, the Brazilian dados.gov.br, Dutch and +Netherland government portals, as well as city and municipal sites in the US, +UK, Argentina, Finland and elsewhere.

    + +

    CKAN: https://ckan.org/
    +CKAN Showcases: https://ckan.org/showcase
    +Features overview: https://ckan.org/features/

    +{% endtrans %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/featured_group.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/featured_group.html new file mode 100644 index 0000000..f411c1e --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/featured_group.html @@ -0,0 +1,7 @@ +{% set groups = h.get_featured_groups() %} + +{% for group in groups %} +
    + {% snippet 'snippets/group_item.html', group=group %} +
    +{% endfor %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/featured_organization.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/featured_organization.html new file mode 100644 index 0000000..d13d18e --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/featured_organization.html @@ -0,0 +1,7 @@ +{% set organizations = h.get_featured_organizations() %} + +{% for organization in organizations %} +
    + {% snippet 'snippets/organization_item.html', organization=organization %} +
    +{% endfor %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/popular_formats.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/popular_formats.html new file mode 100644 index 0000000..d35306a --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/popular_formats.html @@ -0,0 +1,27 @@ +{% set formats = h.get_facet_items_dict('res_format', limit=30) %} + +
    +

    Popular Formats

    +
    + + {% for tag in formats %} + {% set weight = 30 - loop.index %} + {{ h.truncate(tag.display_name, 26) }} + {% endfor %} +
    +
    + + \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/popular_tags.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/popular_tags.html new file mode 100644 index 0000000..585e55e --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/popular_tags.html @@ -0,0 +1,30 @@ +{% set tags = h.get_facet_items_dict('tags', c.search_facets, limit=3) %} + + +
    +

    {{ _('Popular Tags') }}

    +
    + {% for tag in tags %} + {% set weight = 30 - loop.index %} + {{ h.truncate(tag['display_name'], 26) }} + {% endfor %} +
    +

    + See All {{_('Tags')}} +

    +
    + + + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/promoted.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/promoted.html new file mode 100644 index 0000000..ab4dcd3 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/promoted.html @@ -0,0 +1,27 @@ +{% set intro = g.site_intro_text %} + +
    +
    + {% if intro %} + {{ h.render_markdown(intro) }} + {% else %} + {% block home_image %} + + {% endblock %} +
    +

    Welcome to the {{g.site_title}}!

    +

    +Here you will find data and other resources hosted by the D4Science.org infrastructure.

    +

    The catalogue contains a wealth of resources resulting from several activities, projects and communities including BlueBRIDGE (www.bluebridge-vres.eu), i-Marine (www.i-marine.eu), SoBigData.eu (www.sobigdata.eu), and (FAO www.fao.org). +

    +

    All the products are accompanied with rich descriptions capturing general attributes, e.g. title and creator(s), as well as usage policies and licences.

    +
    + {% endif %} +
    +
    diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search.html new file mode 100644 index 0000000..bb27776 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search.html @@ -0,0 +1,22 @@ +{% set tags = h.get_facet_items_dict('tags', search_facets, limit=3) %} +{% set placeholder = _('E.g. environment') %} +{% set dataset_type = h.default_package_type() %} + + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_groups.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_groups.html new file mode 100644 index 0000000..6f31bfd --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_groups.html @@ -0,0 +1,35 @@ +{% set groups = h.d4science_get_browse_info_for_organisations_or_groups(type='group', limit=10) %} +{% set type = 'group' %} +{% if groups|length > 0 %} +
    +
    +

    Browse by {{_('Groups')}}

    + +
    + + {% for index in range(0,groups|length) %} + {% set offset = 5 %} + {% set group = groups[index] %} + {% if index % offset == 0 %} + + {% endif %} + + {% if (index+offset+1) % offset == 0 %} + + {% endif %} + {% endfor %} +
    + {% set url = h.url_for(type ~ '_read', action='read', id=group['name']) %} + + + {{ group['name'] }} +

    {{ group['display_name'] }} ({{group['package_count']}})

    +
    +
    +
    +

    + See All {{_('Groups')}} +

    +
    +
    +{% endif %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_location.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_location.html new file mode 100644 index 0000000..4b88bd2 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_location.html @@ -0,0 +1,44 @@ +{% set alternative_url_dataset = h.url_for(controller='dataset', action='search') %} +{% set locations = h.d4science_get_location_to_bboxes() %} +
    +
    +

    Browse by Location Extent

    +
    + + {% set offset = 5 %} + {% for key, value in locations.items() %} + {% set index = loop.index0 %} + {% if index % offset == 0 %} + + {% endif %} + + {% if (index+offset+1) % offset == 0 %} + + {% endif %} + {% endfor %} +
    + {% set loc = key %} + {% set bbox = value %} + + {{ loc }} +
    +
    +
    + {# ADDED BY FRANCESCO MANGIACRAPA SEE #12651 #} + {% snippet 'spatial/snippets/spatial_query.html', alternative_url=alternative_url_dataset %} + {# END #} +
    +
    + +
    \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_organisations.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_organisations.html new file mode 100644 index 0000000..65b8acb --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_organisations.html @@ -0,0 +1,33 @@ +{% set organizations = h.d4science_get_browse_info_for_organisations_or_groups(type='organization', limit=10) %} +{% set type = 'organization' %} +{% if organizations|length > 1 %} +
    +
    +

    Browse by {{_('Organizations')}}

    +
    + + {% for index in range(0,organizations|length) %} + {% set offset = 5 %} + {% set organization = organizations[index] %} + {% if index % offset == 0 %} + + {% endif %} + + {% if (index+offset+1) % offset == 0 %} + + {% endif %} + {% endfor %} +
    + {% set url = h.url_for(type ~ '_read', action='read', id=organization['name']) %} + + {{ organization['name'] }} +

    {{ organization['display_name'] }} ({{organization['package_count']}})

    +
    +
    +
    +

    + See All {{_('Organizations')}} +

    +
    +
    +{% endif %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_types.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_types.html new file mode 100644 index 0000000..014bd38 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/search_for_types.html @@ -0,0 +1,37 @@ +{% set metadatatype = h.d4science_theme_get_systemtype_field_dict_from_session() %} +{% set metadatatypes = h.get_facet_items_dict(metadatatype['name'], limit=10) %} +{% if metadatatypes|length > 0 %} +
    +
    +

    Browse by {{_('Types')}}

    + +
    + + {% for index in range(0,metadatatypes|length) %} + {% set offset = 5 %} + {% set type = metadatatypes[index] %} + {% if index % offset == 0 %} + + {% endif %} + + {% if (index+offset+1) % offset == 0 %} + + {% endif %} + {% endfor %} +
    + {% set img_url = h.d4science_get_url_to_icon_for_ckan_entity(type.name, entity_type='type') %} + + {{ type.display_name }} +

    + {{ h.truncate(type.display_name, 26) }} + ({{type.count}}) + +

    +
    +
    +

    + See All {{_('Types')}} +

    +
    +
    +{% endif %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/stats.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/stats.html new file mode 100644 index 0000000..c70d596 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/home/snippets/stats.html @@ -0,0 +1,29 @@ +{% set stats = h.get_site_statistics() %} + + diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/autoform.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/autoform.html new file mode 100644 index 0000000..c469b81 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/autoform.html @@ -0,0 +1,70 @@ +{# +Builds a form from the supplied form_info list/tuple. All form info dicts +can also contain an "extra_info" key which will add some help text after the +input element. + +form_info - A list of dicts describing the form field to build. +data - The form data object. +errors - The form errors object. +error_summary - A list of errors to display above the fields. + +Example + + {% set form_info = [ + {'name': 'ckan.site_title', 'control': 'input', 'label': _('Site Title'), 'placeholder': ''}, + {'name': 'ckan.theme', 'control': 'select', 'options': styles, 'label': _('Style'), 'placeholder': ''}, + {'name': 'ckan.site_description', 'control': 'input', 'label': _('Site Tag Line'), 'placeholder': ''}, + {'name': 'ckan.site_logo', 'control': 'input', 'label': _('Site Tag Logo'), 'placeholder': ''}, + {'name': 'ckan.site_about', 'control': 'markdown', 'label': _('About'), 'placeholder': _('About page text')}, + {'name': 'ckan.site_intro_text', 'control': 'markdown', 'label': _('Intro Text'), 'placeholder': _('Text on home page')}, + {'name': 'ckan.site_custom_css', 'control': 'textarea', 'label': _('Custom CSS'), 'placeholder': _('Customisable css inserted into the page header')}, + ] %} + + {% import 'macros/autoform.html' as autoform %} + {{ autoform.generate(form_info, data, errors) }} + +#} +{% import 'macros/form.html' as form %} +{%- macro generate(form_info=[], data={}, errors={}, error_summary=[]) -%} + {{ form.errors(error_summary) if error_summary }} + + {% for item in form_info %} + {% set name = item.name %} + {% set value = data.get(name) %} + {% set error = errors.get(name) %} + {% set id = 'field-%s' % (name|lower|replace('_', '-')|replace('.', '-')) %} + + {% set control = item.control or 'input' %} + {% set label = item.label %} + {% set placeholder = item.placeholder %} + + {% set classes = item.classes or [] %} + {% set classes = ['control-medium'] if not classes and control == 'input' %} + + {% if control == 'select' %} + {% call form.select(name, id=id, label=label, options=item.options, selected=value, error=error) %} + {% if item.extra_info %}{{ form.info(item.extra_info) }}{% endif %} + {% endcall %} + {% elif control == 'html' %} +
    +
    + {{ item.html }} +
    +
    + {% elif control == 'image_upload' %} + {% set field_url = item.field_url or 'image_url' %} + {% set is_upload = data[field_url] and not data[field_url].startswith('http') %} + {% set is_url = data[field_url] and data[field_url].startswith('http') %} + + {% set field_upload = item.field_upload or 'image_upload' %} + {% set field_clear = item.field_clear or 'clear_upload' %} + + {{ form.image_upload(data, errors, is_upload_enabled=item.upload_enabled, is_url=is_url, is_upload=is_upload, upload_label = _('Site logo'), url_label=_('Site logo'), + field_url=field_url, field_upload=field_upload, field_clear=field_clear)}} + {% else %} + {% call form[control](name, id=id, label=label, placeholder=placeholder, value=value, error=error, classes=classes) %} + {% if item.extra_info %}{{ form.info(item.extra_info) }}{% endif %} + {% endcall %} + {% endif %} + {% endfor %} +{%- endmacro -%} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form.html new file mode 100644 index 0000000..f33b7ab --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form.html @@ -0,0 +1,36 @@ +{# +All macros were split into their own template file in `templates/macros/form/`) +and here, we are importing them all to maintain backward compatibility. +#} + +{% from 'macros/form/input.html' import input %} +{% from "macros/form/input_block.html" import input_block %} +{% from 'macros/form/checkbox.html' import checkbox %} +{% from 'macros/form/select.html' import select %} +{% from "macros/form/attributes.html" import attributes %} +{% from "macros/form/markdown.html" import markdown %} +{% from "macros/form/textarea.html" import textarea %}s +{% from "macros/form/prepend.html" import prepend %} +{% from "macros/form/custom.html" import custom %} +{% from "macros/form/errors.html" import errors %} +{% from "macros/form/info.html" import info %} +{% from "macros/form/hidden.html" import hidden %} +{% from "macros/form/hidden_from_list.html" import hidden_from_list %} +{% from "macros/form/required_message.html" import required_message %} +{% from "macros/form/image_upload.html" import image_upload %} + +{% set input = input %} +{% set input_block = input_block %} +{% set checkbox = checkbox %} +{% set select = select %} +{% set attributes = attributes %} +{% set markdown = markdown %} +{% set textarea = textarea %} +{% set prepend = prepend %} +{% set custom = custom %} +{% set errors = errors %} +{% set info = info %} +{% set hidden = hidden %} +{% set hidden_from_list = hidden_from_list %} +{% set required_message = required_message %} +{% set image_upload = image_upload %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/attributes.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/attributes.html new file mode 100644 index 0000000..47359a6 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/attributes.html @@ -0,0 +1,17 @@ +{# +Builds a space seperated list of html attributes from a dict of key/value pairs. +Generally only used internally by macros. + +attrs - A dict of attribute/value pairs + +Example + +{% import 'macros/form.html' as form %} +{{ form.attributes({}) }} + +#} +{%- macro attributes(attrs={}) -%} +{%- for key, value in attrs.items() -%} +{{ " " }}{{ key }}{% if value != "" %}="{{ value }}"{% endif %} +{%- endfor -%} +{%- endmacro -%} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/checkbox.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/checkbox.html new file mode 100644 index 0000000..130720f --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/checkbox.html @@ -0,0 +1,34 @@ +{% from "macros/form/attributes.html" import attributes %} + +{# +Builds a single checkbox input. + +name - The name of the form parameter. +id - The id to use on the input and label. Convention is to prefix with 'field-'. +label - The human readable label. +value - The value of the input. +checked - If true the checkbox will be checked +error - An error string for the field or just true to highlight the field. +classes - An array of classes to apply to the form-group. +is_required - Boolean of whether this input is requred for the form to validate + +Example: + +{% import 'macros/form.html' as form %} +{{ form.checkbox('remember', checked=true) }} + +#} +{% macro checkbox(name, id='', label='', value='', checked=false, placeholder='', error="", classes=[], attrs={}, is_required=false) %} +{%- set extra_html = caller() if caller -%} +
    +
    + + {{ extra_html }} +
    +
    +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/custom.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/custom.html new file mode 100644 index 0000000..4503b05 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/custom.html @@ -0,0 +1,61 @@ +{% from "macros/form/input_block.html" import input_block %} +{% from "macros/form/attributes.html" import attributes %} + +{# +Creates all the markup required for an custom key/value input. These are usually +used to let the user provide custom meta data. Each "field" has three inputs +one for the key, one for the value and a checkbox to remove it. So the arguments +for this macro are nearly all tuples containing values for the +(key, value, delete) fields respectively. + +name - A tuple of names for the three fields. +id - An id string to be used for each input. +label - The human readable label for the main label. +values - A tuple of values for the (key, value, delete) fields. If delete +is truthy the checkbox will be checked. +placeholder - A tuple of placeholder text for the (key, value) fields. +error - A list of error strings for the field or just true to highlight the field. +classes - An array of classes to apply to the form-group. +is_required - Boolean of whether this input is requred for the form to validate + +Examples: + +{% import 'macros/form.html' as form %} +{{ form.custom( +names=('custom_key', 'custom_value', 'custom_deleted'), +id='field-custom', +label=_('Custom Field'), +values=(extra.key, extra.value, extra.deleted), +error='' +) }} +#} +{% macro custom(names=(), id="", label="", values=(), placeholders=(), error="", classes=[], attrs={}, is_required=false, key_values=()) %} +{%- set classes = (classes|list) -%} +{%- set label_id = (id or names[0]) ~ "-key" -%} +{%- set extra_html = caller() if caller -%} +{%- do classes.append('control-custom') -%} + +{% call input_block(label_id, label or name, error, classes, control_classes=["editor"], extra_html=extra_html, is_required=is_required) %} +
    +
    +
    + + +
    +
    +
    + {% if values[0] or values[1] or error %} + + {% endif %} +
    + + +
    +
    +
    + +{% endcall %} +{% endmacro %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/errors.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/errors.html new file mode 100644 index 0000000..9f55bad --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/errors.html @@ -0,0 +1,26 @@ +{# +Builds a list of errors for the current form. + +errors - A dict of field/message pairs. +type - The alert-* class that should be applied (default: "error") +classes - A list of classes to apply to the wrapper (default: []) + +Example: + +{% import 'macros/form.html' as form %} +{{ form.errors(error_summary, type="warning") }} + +#} + +{% macro errors(errors={}, type="error", classes=[]) %} +{% if errors %} +
    +

    {{ _('The form contains invalid entries:') }}

    +
      + {% for key, error in errors.items() %} +
    • {% if key %}{{ key }}: {% endif %}{{ error }}
    • + {% endfor %} +
    +
    +{% endif %} +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/hidden.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/hidden.html new file mode 100644 index 0000000..ad46447 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/hidden.html @@ -0,0 +1,14 @@ +{# +Builds a single hidden input. + +name - name of the hidden input +value - value of the hidden input + +Example +{% import 'macros/form.html' as form %} +{{ form.hidden('name', 'value') }} + +#} +{% macro hidden(name, value) %} + +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/hidden_from_list.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/hidden_from_list.html new file mode 100644 index 0000000..60e0d16 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/hidden_from_list.html @@ -0,0 +1,28 @@ +{% from "macros/form/hidden.html" import hidden %} + +{# +Contructs hidden inputs for each name-value pair. + +fields - [('name1', 'value1'), ('name2', 'value2'), ...] + +Two parameter for excluding several names or name-value pairs. + +except_names - list of names to be excluded +except - list of name-value pairs to be excluded + + +Example: +{% import 'macros/form.html' as form %} +{% form.hidden_from_list(fields=c.fields, except=[('topic', 'xyz')]) %} +{% form.hidden_from_list(fields=c.fields, except_names=['time_min', 'time_max']) %} +#} +{% macro hidden_from_list(fields, except_names=None, except=None) %} +{% set except_names = except_names or [] %} +{% set except = except or [] %} + +{% for name, value in fields %} +{% if name and value and name not in except_names and (name, value) not in except %} +{{ hidden(name, value) }} +{% endif %} +{% endfor %} +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/image_upload.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/image_upload.html new file mode 100644 index 0000000..1f35a0b --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/image_upload.html @@ -0,0 +1,59 @@ +{% from 'macros/form/input.html' import input %} +{% from 'macros/form/checkbox.html' import checkbox %} + +{# +Builds a file upload for input + +Example +{% import 'macros/form.html' as form %} +{{ form.image_upload(data, errors, is_upload_enabled=true) }} + +#} +{% macro image_upload(data, errors, field_url='image_url', field_upload='image_upload', field_clear='clear_upload', + is_url=false, is_upload=false, is_upload_enabled=false, placeholder=false, + url_label='', upload_label='', field_name='image_url') %} +{% set placeholder = placeholder if placeholder else _('http://example.com/my-image.jpg') %} +{% set url_label = url_label or _('Image URL') %} +{% set upload_label = upload_label or _('Image') %} +{% set previous_upload = data['previous_upload'] %} + +{% if field_url == 'url' and field_upload == 'upload' %} + {# backwards compatibility for old resource forms that still call the `forms.image_upload()` macro, eg ckanext-scheming #} + {% snippet 'package/snippets/resource_upload_field.html', + data=data, + errors=errors, + is_url=is_url, + is_upload=is_upload, + is_upload_enabled=is_upload_enabled, + url_label=url_label, + upload_label=upload_label, + placeholder=placeholder %} +{% else %} + {% if is_upload_enabled %} +
    + {% endif %} + + + {{ input(field_url, label=url_label, id='field-image-url', type='url', placeholder=placeholder, value=data.get(field_url), error=errors.get(field_url), classes=['control-full']) }} + + + {% if is_upload_enabled %} + {{ input(field_upload, label=upload_label, id='field-image-upload', type='file', placeholder='', value='', error='', classes=['control-full']) }} + {% if is_upload %} + {{ checkbox(field_clear, label=_('Clear Upload'), id='field-clear-upload', value='true', error='', classes=['control-full']) }} + {% endif %} + {% endif %} + + {% if is_upload_enabled %}
    {% endif %} +{% endif %} + +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/info.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/info.html new file mode 100644 index 0000000..54ecc84 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/info.html @@ -0,0 +1,24 @@ +{# +Renders an info box with a description. This will usually be used with in a +call block when creating an input element. + +text - The text to include in the box. +inline - If true displays the info box inline with the input. +classes - A list of classes to add to the info box. + +Example + +{% import 'macros/form.html' as form %} +{% call form.input('name') %} +{{ form.info(_('My useful help text')) }} +{% endcall %} + +#} +{% macro info(text='', inline=false, classes=[]) %} +{%- if text -%} +
    + +{{ text }} +
    +{%- endif -%} +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/input.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/input.html new file mode 100644 index 0000000..d7f7c29 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/input.html @@ -0,0 +1,30 @@ +{% from "macros/form/input_block.html" import input_block %} +{% from "macros/form/attributes.html" import attributes %} + +{# +Creates all the markup required for an input element. Handles matching labels to +inputs, error messages and other useful elements. + +name - The name of the form parameter. +id - The id to use on the input and label. Convention is to prefix with 'field-'. +label - The human readable label. +value - The value of the input. +placeholder - Some placeholder text. +type - The type of input eg. email, url, date (default: text). +error - A list of error strings for the field or just true to highlight the field. +classes - An array of classes to apply to the form-group. +is_required - Boolean of whether this input is requred for the form to validate + +Examples: + +{% import 'macros/form.html' as form %} +{{ form.input('title', label=_('Title'), value=data.title, error=errors.title) }} + +#} +{% macro input(name, id='', label='', value='', placeholder='', type='text', error="", classes=[], attrs={'class': 'form-control'}, is_required=false) %} +{%- set extra_html = caller() if caller -%} + +{% call input_block(id or name, label or name, error, classes, extra_html=extra_html, is_required=is_required) %} + +{% endcall %} +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/input_block.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/input_block.html new file mode 100644 index 0000000..6f7e691 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/input_block.html @@ -0,0 +1,32 @@ +{# +A generic input_block for providing the default markup for CKAN form elements. +It is expected to be called using a {% call %} block, the contents of which +will be inserted into the .controls element. + +for - The id for the input that the label should match. +label - A human readable label. +error - A list of error strings for the field or just true. +classes - An array of custom classes for the outer element. +control_classes - An array of custom classes for the .control wrapper. +extra_html - An html string to be inserted after the errors eg. info text. +is_required - Boolean of whether this input is requred for the form to validate + +Example: + +{% import 'macros/form.html' as form %} +{% call form.input_block("field", "My Field") %} + +{% endcall %} + +#} + +{% macro input_block(for, label="", error="", classes=[], control_classes=[], extra_html="", is_required=false) %} +
    + +
    +{{ caller() }} +{% if error and error is iterable %}{{ error|join(', ') }}{% endif %} +{{ extra_html }} +
    +
    +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/markdown.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/markdown.html new file mode 100644 index 0000000..59b4a1d --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/markdown.html @@ -0,0 +1,33 @@ +{% from "macros/form/input_block.html" import input_block %} +{% from "macros/form/attributes.html" import attributes %} + +{# +Creates all the markup required for a Markdown textarea element. Handles +matching labels to inputs, selected item and error messages. + +name - The name of the form parameter. +id - The id to use on the input and label. Convention is to prefix with 'field-'. +label - The human readable label. +value - The value of the input. +placeholder - Some placeholder text. +error - A list of error strings for the field or just true to highlight the field. +classes - An array of classes to apply to the form-group. +is_required - Boolean of whether this input is requred for the form to validate + +Examples: + +{% import 'macros/form.html' as form %} +{{ form.markdown('desc', id='field-description', label=_('Description'), value=data.desc, error=errors.desc) }} + +#} +{% macro markdown(name, id='', label='', value='', placeholder='', error="", classes=[], attrs={'class': 'form-control'}, is_required=false) %} +{% set classes = (classes|list) %} +{% do classes.append('control-full') %} +{% set markdown_tooltip = "

    __Bold text__ or _italic text_

    # title
    ## secondary title
    ### etc

    * list
    * of
    * items

    http://auto.link.ed/

    Full markdown syntax

    Please note: HTML tags are stripped out for security reasons

    " %} + +{%- set extra_html = caller() if caller -%} +{% call input_block(id or name, label or name, error, classes, control_classes=["editor"], extra_html=extra_html, is_required=is_required) %} + +{% trans %}You can use Markdown formatting here{% endtrans %} +{% endcall %} +{% endmacro %} diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/prepend.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/prepend.html new file mode 100644 index 0000000..1441343 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/prepend.html @@ -0,0 +1,38 @@ +{% from "macros/form/input_block.html" import input_block %} +{% from "macros/form/attributes.html" import attributes %} + +{# +Creates all the markup required for an input element with a prefixed segment. +These are useful for showing url slugs and other fields where the input +information forms only part of the saved data. + +name - The name of the form parameter. +id - The id to use on the input and label. Convention is to prefix with 'field-'. +label - The human readable label. +prepend - The text that will be prepended before the input. +value - The value of the input. +which will use the name key as the value. +placeholder - Some placeholder text. +error - A list of error strings for the field or just true to highlight the field. +classes - An array of classes to apply to the form-group. +is_required - Boolean of whether this input is requred for the form to validate + +Examples: + +{% import 'macros/form.html' as form %} +{{ form.prepend('slug', id='field-slug', prepend='/dataset/', label=_('Slug'), value=data.slug, error=errors.slug) }} + +#} +{% macro prepend(name, id='', label='', prepend='', value='', placeholder='', type='text', error="", classes=[], attrs={'class': 'form-control'}, is_required=false) %} +{# We manually append the error here as it needs to be inside the .input-group block #} +{% set classes = (classes|list) %} +{% do classes.append('error') if error %} +{%- set extra_html = caller() if caller -%} +{% call input_block(id or name, label or name, error='', classes=classes, extra_html=extra_html, is_required=is_required) %} +
    + {% if prepend %}{%- endif -%} + + {% if error and error is iterable %}{{ error|join(', ') }}{% endif %} +
    +{% endcall %} +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/required_message.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/required_message.html new file mode 100644 index 0000000..f5a4cc7 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/required_message.html @@ -0,0 +1,13 @@ +{# +Outputs the "* Required field" message for the bottom of formss + +Example +{% import 'macros/form.html' as form %} +{{ form.required_message() }} + +#} +{% macro required_message() %} +

    + * {{ _("Required field") }} +

    +{% endmacro %} \ No newline at end of file diff --git a/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/select.html b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/select.html new file mode 100644 index 0000000..15a1025 --- /dev/null +++ b/compose/2.10/src/ckanext-d4science_theme/ckanext/d4science_theme/templates/macros/form/select.html @@ -0,0 +1,50 @@ +{% from "macros/form/input_block.html" import input_block %} +{% from "macros/form/attributes.html" import attributes %} + +{# +Creates all the markup required for an select element. Handles matching labels to +inputs and error messages. + +A field should be a dict with a "value" key and an optional "text" key which +will be displayed to the user. We use a dict to easily allow extension in +future should extra options be required. + +name - The name of the form parameter. +id - The id to use on the input and label. Convention is to prefix with 'field-'. +label - The human readable label. +options - A list/tuple of fields to be used as . + selected - The value of the selected