diff --git a/.env.template b/.env.template new file mode 100644 index 00000000..fd7e128b --- /dev/null +++ b/.env.template @@ -0,0 +1,132 @@ +# Solr setting +SOLR_URL_SCHEME=http +SOLR_HOST=solr +SOLR_PORT=8983 +SOLR_CORE=hyrax_production +SOLR_TEST_PORT=8985 + +# Database setting +POSTGRES_HOST_APP=appdb +POSTGRES_HOST_FCREPO=fcrepodb +POSTGRES_PORT=5432 +POSTGRES_USER=postgres +POSTGRES_PASSWORD=password +POSTGRES_DB_APP=hyrax_production +POSTGRES_DB_FCREPO=fcrepo + +# Redis setting +REDIS_HOST=redis +REDIS_PORT=6379 + +# Fedora setting +FEDORA_URL_SCHEME=http +FEDORA_HOST=fcrepo +FEDORA_PORT=8080 +# FCREPO_ENDPOINT=hyrax_production # Optional - default is production +# FCREPO_PATH='/rest' # Optional - default is /fcrepo/rest +FCREPO_VERSION=4.7.5 +FEDORA_TEST_PORT=8986 + +# RAILS setting +LANG=C.UTF-8 +PORT=3000 +RAILS_ENV=production +RAILS_LOG_TO_STDOUT=true +RAILS_SERVE_STATIC_FILES=true +RAILS_MAX_THREADS=5 +# The secrect key should be a very long random key. +# You can use "$ bundle exec rails secret" to generate one. +SECRET_KEY_BASE= +DEVISE_SECRET_KEY= + +# Google analytics setting for the application +GOOGLE_ANALYTICS_ID= +GA_APP_NAME= +GA_APP_VERSION= +GA_PRIVATE_KEY_PATH= +GA_PRIVATE_KEY_SECRET= +GA_CLIENT_EMAIL= + +# Hyrax application setting +# NB: in macOS Catalina (10.15) the /srv/ path is not available to Docker +HOST_APP_DATA_PATH=/srv/ngdr/data/ +DERIVATIVES_PATH=/shared/derivatives/ +FITS_PATH=/fits/fits-1.3.0/fits.sh +# fits_version should appear exactly like this, including fits- +FITS_VERSION=fits-1.3.0 +UPLOADS_PATH=/shared/uploads/ +CACHE_PATH=/shared/cache/ +BRAND_PATH=/data/public/branding +DEFAULT_DATE_FORMAT=%d/%m/%Y +NOTIFICATIONS_EMAIL_DEFAULT_FROM_ADDRESS="no-reply@mailboxer.com" +USER_MANAGEMENT_EMAIL_FROM_ADDRESS=repo-admin@example.org +CONTACT_FORM_SUBJECT_PREFIX=Hyrax Contact form: +CONTACT_EMAIL= +FROM_EMAIL= +SMTP_PASS= +GEONAMES= +IIIF_SEARCH_ENDPOINT= +CONFIG_IIIF_IMAGE_ENDPOINT= +# If the rails server is configured to serve requests in https, set this to true +IIIF_TO_SERVE_SSL_URLS=false + +# errbit setup +# Host where errbit server is installed. Start with http or https +AIRBRAKE_HOST= +# Any positive integer should work +AIRBRAKE_PROJECT_ID= +# The project key to authorize loggint with errbit server +AIRBRAKE_PROJECT_KEY= + +# Browse Everything credentials +GOOGLE_DRIVE_CLIENT_ID= +GOOGLE_DRIVE_CLIENT_SECRET= +BOX_CLIENT_ID= +BOX_CLIENT_SECRET= + +# Choose one of the following authentication methods. +# (database_authenticatable is pre-configured and useful for a development environment) +MDR_DEVISE_AUTH_MODULE=database_authenticatable +# MDR_DEVISE_AUTH_MODULE=ldap_authenticatable +# MDR_DEVISE_AUTH_MODULE=cas_authenticatable + +LDAP_HOST=***REMOVED*** +LDAP_PORT=443 +LDAP_ATTRIBUTE=uid +LDAP_BASE=***REMOVED*** +LDAP_ADMIN_USER=***REMOVED*** +LDAP_ADMIN_PASSWORD=***REMOVED*** +LDAP_SSL=false + +SMTP_HOST= +SMTP_PORT= + +MDR_HOST= + +CAS_BASE_URL=https://cas.nims.go.jp/ + +# For local docker-based setup for development, use: +# CAS_BASE_URL=https://cas.mdr.nims.test:8443/cas/ +# and add the following two localhost pointers to your system's /etc/hosts file: +# 127.0.0.1 mdr.nims.test # <-- MDR website +# 127.0.0.1 cas.mdr.nims.test # <-- CAS server +# and also trust the SSL certificate for cas.mdr.nims.test + +# CAS_VALIDATE_URL may need to be set depending on how MDR is configured +# CAS_VALIDATE_URL=https://cas:8443/cas/serviceValidate +# CAS_DESTINATION_URL=https://portal.nims.test/ + +# OAI config used in config/initializers/oai_config.rb +OAI_REPOSTIORY_NAME='NIMS MDR' +OAI_REPOSITORY_URL=http://localhost:3000/catalog/oai +OAI_RECORD_PREFIX=nims_mdr +OAI_ADMIN_EMAIL=***REMOVED*** + +# User Authorisation LDAP (runs after database / LDAP / CAS authentication) +USER_AUTHORISATION_LDAP_HOST= +USER_AUTHORISATION_LDAP_PORT=389 +USER_AUTHORISATION_LDAP_ATTRIBUTE=uid +USER_AUTHORISATION_LDAP_BASE= + +WIKIBASE_BASE_URL=https://wikibase.example.jp +WIKIBASE_SPARQL_QUERY_SYNONYM=/query/example?query=some_sparql_query diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..402e4001 --- /dev/null +++ b/.gitignore @@ -0,0 +1,354 @@ +### nims-hyrax project specific +.idea/ + +# ignore files for puma but keep directory structure +hyrax/shared/log/* +!hyrax/shared/log/.keep +hyrax/shared/pids/* +!hyrax/shared/pids/.keep +hyrax/shared/sockets/* +!hyrax/shared/sockets/.keep + +# Files that appeared when I ran hyrax that weren't initally checked in +.generators +.rakeTasks + +# commented out .rspec in ruby template below (since it was in git already) + +# public assets generated files +hyrax/public/assets + +# Created by .ignore support plugin (hsz.mobi) +### Ansible template +*.retry +### Emacs template +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el +### Rails template +*.rbc +capybara-*.html +#.rspec +/log +/tmp +/db/*.sqlite3 +/db/*.sqlite3-journal +/public/system +/coverage/ +/hyrax/coverage +/spec/tmp +*.orig +rerun.txt +pickle-email-*.html +hyrax/docs + +# TODO Comment out this rule if you are OK with secrets being uploaded to the repo +config/initializers/secret_token.rb +config/master.key + +# Only include if you have production secrets in this file, which is no longer a Rails default +# config/secrets.yml + +## Environment normalization: +/.bundle +/vendor/bundle + +# these should all be checked in to normalize the environment: +# Gemfile.lock, .ruby-version, .ruby-gemset + +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: +.rvmrc + +# if using bower-rails ignore default bower_components path bower.json files +/vendor/assets/bower_components +*.bowerrc +bower.json + +# Ignore pow environment settings +.powenv + +# Ignore Byebug command history file. +.byebug_history + +# Ignore node_modules +node_modules/ + +### Vim template +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-v][a-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ +### SublimeText template +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/dictionaries +.idea/**/shelf + +# 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 + +# CMake +cmake-build-debug/ +cmake-build-release/ + +# 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 + +# 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 +### Terraform template +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Ignore any .tfvars files that are generated automatically for each Terraform run. Most +# .tfvars files are managed as part of configuration and so should be included in +# version control. +# +# example.tfvars +### Ruby template +*.gem +*.rbc +/.config +/coverage/ +/InstalledFiles +/pkg/ +/spec/reports/ +/spec/examples.txt +/test/tmp/ +/test/version_tmp/ +/tmp/ + +# Used by dotenv library to load environment variables. +# .env + +## Specific to RubyMotion: +.dat* +.repl_history +build/ +*.bridgesupport +build-iPhoneOS/ +build-iPhoneSimulator/ + +## Specific to RubyMotion (use of CocoaPods): +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# vendor/Pods/ + +## Documentation cache and generated files: +/.yardoc/ +/_yardoc/ +/doc/ +/rdoc/ + +## Environment normalization: +/.bundle/ +/vendor/bundle +/lib/bundler/man/ + +# for a library or gem, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# Gemfile.lock +# .ruby-version +# .ruby-gemset + +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: +.rvmrc +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Environment variables file +.env.production +.env +/hyrax/.fedora-test.pid +/hyrax/.solr-test.pid +cas/.mvn/jvm.config diff --git a/README.md b/README.md new file mode 100644 index 00000000..db4ef2f1 --- /dev/null +++ b/README.md @@ -0,0 +1,277 @@ +## Introduction + +[Nims-Hyrax](https://github.com/antleaf/nims-hyrax/) is an implementation of the Hyrax stack by [Cottage Labs](http://cottagelabs.com/) and [AntLeaf](http://antleaf.com/). It is built with Docker containers, which simplify development and deployment onto live services. + + +## Getting Started + +Clone the repository with `git clone https://github.com/antleaf/nims-hyrax.git`. + +Ensure you have docker and docker-compose. See [notes on installing docker](https://github.com/antleaf/nims-hyrax/blob/develop/README.md#installing-docker). + +Open a console and try running `docker -h` and `docker-compose -h` to verify they are both accessible. + +Create the environment file `.env`. You can start by copying the template file [.env.template](https://github.com/antleaf/nims-hyrax/blob/develop/.env.template) to `.env` and customizing the values to your setup. + +## quick start +If you would like to do a test run of the system, start the docker containers +```bash +$ cd nims-hyrax +$ docker-compose up -d +``` +You should see the containers being built and the services start. + +### For Development +We use the [Git Flow](https://nvie.com/posts/a-successful-git-branching-model/) branching model, so ensure you set up +your project directory by running `git flow init` and accept the defaults. +[Installation for git-flow](https://github.com/nvie/gitflow/wiki/Installation). + +```shell +Branch name for production releases: [master] +Branch name for "next release" development: [develop] +Feature branches? [feature/] +Bugfix branches? [bugfix/] +Release branches? [release/] +Hotfix branches? [hotfix/] +Support branches? [support/] +Version tag prefix? [] +Hooks and filters directory? [/nims-hyrax/.git/hooks] +``` + +The default branch in this repository is `develop`, and `master` should be used for stable releases only. After +finishing bugfixes or releases with `git-flow` remember to also push tags with `git push --tags`. + +New code is created in `feature/` or `hotfix/` branches, and from there we make a pull request against the develop branch. A member of the team other than the new code's author reviews the pull request and performs the merge. Codeship tests run when the `develop` branch is updated. + +## Guide to docker-compose and the services needed to run the materials data repository + +![services diagram](https://github.com/antleaf/nims-hyrax/blob/develop/hyrax/docs/container_diag.png) + + +There are 4 `docker-compose` files provided in the repository, which build the containers running the services as shown above + * [docker-compose.yml](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.yml) is the main docker-compose file. It builds all the core servcies required to run the application + * [fcrepo](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.yml#L16-L27) is the container running the [Fedora 4 commons repository](https://wiki.duraspace.org/display/FEDORA47/Fedora+4.7+Documentation), an rdf document store. By default, this runs the fedora service on port 8080 internally in docker (http://fcrepo:8080/fcrepo/rest).

+ * [Solr container](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.yml#L29-L46) runs [SOLR](lucene.apache.org/solr/), an enterprise search server. By default, this runs the SOLR service on port 8983 internally in docker (http://solr:8983).

+ * [db container](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.yml#L48-L60) running a postgres database, used by the Hyrax application. By default, this runs the database service on port 5432 internally in docker.

+ * [redis container](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.yml#L109-L125) running [redis](https://redis.io/), used by Hyrax to manage background tasks. By default, this runs the redis service on port 6379 internally in docker.

+ * [app container](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.yml#L62-L81) sets up the [Hyrax] application, which is then used by 2 services - web and workers.

+ * [Web container](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.yml#L83-L94) runs the materials data repository application. By default, this runs the materials data repository service on port 3000 internally in docker (http://web:3000).

This container runs [docker-entrypoint.sh](https://github.com/antleaf/nims-hyrax/blob/develop/hyrax/docker-entrypoint.sh). It needs the database, solr and fedora containers to be up and running. It waits for 15s to ensure Solr and fedora are running and exits if they are not. It [runs a rake task](https://github.com/antleaf/nims-hyrax/blob/develop/hyrax/docker-entrypoint.sh#L38-L39), ([setup_hyrax.rake](https://github.com/antleaf/nims-hyrax/blob/develop/hyrax/lib/tasks/setup_hyrax.rake)) to setup the application.

The default workflows are loaded, the default admin set and collection types are created and the users in [setup.json](https://github.com/antleaf/nims-hyrax/blob/develop/hyrax/seed/setup.json) are created as a part of the setup.

+ * [Wokers container](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.yml#L96-L107) runs the background tasks for materials data repository, using [sidekiq](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=2ahUKEwio06ew2qPhAhUMZt4KHT0jDwQQFjAAegQIBBAB&url=https%3A%2F%2Fgithub.com%2Fmperham%2Fsidekiq&usg=AOvVaw3mZXHmVT7i5YYB8_u56eH2) and redis. By default, this runs the worker service.

Hyrax processes long-running or particularly slow work in background jobs to speed up the web request/response cycle. When a user submits a file through a work (using the web or an import task), there a humber of background jobs that are run, initilated by the hyrax actor stack, as explained [here](https://samvera.github.io/what-happens-deposit-2.0.html)

You can monitor the background workers using the materials data repository service at http://web:3000/sidekiq when logged in as an admin user.

+ * [docker-compose.override.yml](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose.override.yml) This file exposes the ports for fcrepo, solr and the hyrax web container, so they an be accessed outside the container. If running this service in development or test, we could use this file.

+ * [docker-compose-demo.yml](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose-demo.yml) builds the [nginx container](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose-demo.yml#L15-L26) running the nginx service, which will reverse proxy requests from the web service, run by the web container. This will expose port 443 to the users, so they can interact with the materials data repository.

+ There is also a http basic authentication requested by nginx. The credentials can be generated with the `htpasswd` command from the `apache2-utils` package (on Ubuntu) and the htpasswd file should be in the [docker/nginx directory](https://github.com/antleaf/nims-hyrax/tree/develop/docker/nginx).

+ To change or remove the http auth, edit the config in [docker/nginx/nginx.conf](https://github.com/antleaf/nims-hyrax/blob/develop/docker/nginx/nginx.conf) and the `.htpasswd` file.

+ The domain name would need to modified to one you are going to use for your service in the nginx.conf file.

The nginx container will automatically try to ascertain free-of-charge a [Certbot / LetsEncrypt](https://certbot.eff.org) certificate, it it has access to the server, to check the domain name resolves.

In order for the certificate verification to succeed, it is important not to destroy and recreate the nginx container's volumes so fast as to hit the Certbot rate limit for new certificates. In addition, ports 80 and 443 on our application must be accessible from the Certbot servers (i.e. not blocked by firewall).

It is very likely that you will need to replace the nginx.conf file to one that suits your deployment environment. + * [docker-compose-production.yml](https://github.com/antleaf/nims-hyrax/blob/develop/docker-compose-production.yml) is the production configuration, customised for the infrastructure at NIMS.

+ + +The data for the application is stored in docker named volumes as specified by the compose files. These are: + +```bash +$ docker volume list +nims-hyrax_cache +nims-hyrax_db +nims-hyrax_derivatives +nims-hyrax_fcrepo +nims-hyrax_file_uploads +nims-hyrax_letsencrypt +nims-hyrax_redis +nims-hyrax_solr_home +``` + +These will persist when the system is brought down and rebuilt. Deleting them will require importers etc. to run again. + + +## Running in development or test + +When running in development and test environment use `docker-compose`. This will use the docker-compose.yml file and the docker-compose.override.yml file and not use the docker-compose-production.yml. + * fcrepo container will run the fedora service, which will be available in port 8080 at http://localhost:8080/fcrepo/rest + * Solr container will run the Solr service, which will be available in port 8983 at http://localhost:8983 + * The web container runs the materials data repository service, which will be available in port 3000 at http://localhost:3000 + +You could setup an alias for docker-compose on your local machine, to ease typing + +```bash +alias ngdrdocker='docker-compose -f docker-compose.yml -f docker-compose.override.yml' +``` +which is by default the same as +```bash +alias ngdrdocker='docker-compose' +``` + +## Running in production + +When running in production, you need to use `docker-compose -f docker-compose.yml -f docker-compose-production.yml`, replacing docker-compose.override.yml with docker-compose-production.yml. To assist this, an alias similar to that below can be useful: + +```bash +alias ngdrdocker='docker-compose -f docker-compose.yml -f docker-compose-production.yml' +``` + +* The service will run without the ports of intermediary services such as Solr being exposed to the host. +* Materials data repository is accessible behind http basic auth at port 443, http requests to port 80 will be redirected to https. +* In the current nginx setup, access credentials are needed. + +## Builidng, starting and managing the service with docker + +### Build the docker container + +To start with, you would need to build the system, before running the services. To do this you need to issue the `build` command +```bash +$ ngdrdocker build +``` +Note: This is using the alias defined above, as a short form for
+In development: +```bash +$ docker-compose build +``` +In production: +```bash +$ docker-compose -f docker-compose.yml -f docker-compose-production.yml build +``` + +### Start and run the services in the containers + +To run the containers after build, issue the `up` command (-d means run as daemon, in the background): + +```bash +ngdrdocker up -d +``` +Note: This is using the alias defined above, as a short form for
+In development: +```bash +$ docker-compose up -d +``` +In production: +```bash +$ docker-compose -f docker-compose.yml -f docker-compose-production.yml up -d +``` + +The containers should all start and the services should be available in their end points as described above +* web server at http://localhost:3000 in development and https://domain-name in production + +### docker container status and logs + +You can see the state of the containers with `docker-compose ps`, and view logs e.g. for the web container using `docker-compose logs web` + +The services that you would need to monitor the logs for are docker mainly web and workers. + + +### Some example docker commands and usage: + +[Docker cheat sheet](https://github.com/wsargent/docker-cheat-sheet) + +```bash +# Bring the whole application up to run in the background, building the containers +ngdrdocker up -d --build + +# Halt the system +ngdrdocker down + +# Re-create the nginx container without affecting the rest of the system (and run in the background with -d) +ngdrdocker up -d --build --no-deps --force-recreate nginx + +# View the logs for the web application container +ngdrdocker logs web + +# Create a log dump file +ngdrdocker logs web | tee web_logs_`date --iso-8601` +# (writes to e.g. web_logs_2019-03-27) + +# View all running containers +docker ps +# (example output:) +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +f42cf90d4494 nims-hyrax_nginx "sh -c 'nginx && cer…" 5 days ago Up 5 days 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nims-hyrax_nginx_1 +6da65933de09 nims-hyrax_web "bash -c /bin/docker…" 5 days ago Up 14 hours 3000/tcp nims-hyrax_web_1 +ab9600b12f2d nims-hyrax_workers "bundle exec sidekiq" 5 days ago Up 5 days nims-hyrax_workers_1 +a9e18ff5eef7 ualbertalib/docker-fcrepo4:4.7 "catalina.sh run" 5 days ago Up 5 days 8080/tcp nims-hyrax_fcrepo_1 +8a31c9b41e54 nims-hyrax_solr "/docker-entrypoint.…" 5 days ago Up 5 days (healthy) 8983/tcp nims-hyrax_solr_1 +4382df4d4033 nims-hyrax_db "docker-entrypoint.s…" 5 days ago Up 5 days (healthy) 5432/tcp nims-hyrax_db_1 +7580bf933d43 redis:5 "docker-entrypoint.s…" 5 days ago Up 5 days (healthy) 6379/tcp nims-hyrax_redis_1 + +# Using its container name, you can run a shell in a container to view or make changes directly +docker exec -it nims-hyrax_nginx_1 sh +``` + +#### Installing Docker + +On `saku05` and the demo server on Digital Ocean we use docker version 18.09.3, and docker-compose version 1.23.2 + +1. Install Docker [by following step 1 of the Docker Compose installation tutorial](https://docs.docker.com/compose/install/) on your machine. + +2. Make sure you don't need to `sudo` to run docker. [Instructions on set-up and how to test that it works.](https://docs.docker.com/engine/installation/linux/ubuntulinux/#/manage-docker-as-a-non-root-user) + +3. Install [Docker Compose by following steps 2 and onwards from the Docker Compose installation Tutorial](https://docs.docker.com/compose/install/). + +> Ubuntu Linux users, the command that Docker-Compose provides you with will not work since /usr/local/bin is not writeable by anybody but root in default Ubuntu setups. Use `sudo tee` instead, e.g.: + +```bash +$ curl -L https://github.com/docker/compose/releases/download/[INSERT_DESIRED_DOCKER_COMPOSE_VERSION_HERE]/docker-compose-`uname -s`-`uname -m` | sudo tee /usr/local/bin/docker-compose > /dev/null && sudo chmod a+x /usr/local/bin/docker-compose +``` + +4. Open a console and try running `docker -h` and `docker-compose -h` to verify they are both accessible. + + +### Using a local Docker-based CAS server for Single Sign-On and Single Sign-Off + +If you would like to use a local Docker-based CAS server for single sign-on and sign off, a little more configuration is +required. Note that these steps are optional: you could use database authentication or LDAP authentication, or a remote +CAS server instead. + +1. In your system's `/etc/hosts` file, add the following two entries which will redirect the specified hostnames to localhost: + + ``` + 127.0.0.1 mdr.nims.test + 127.0.0.1 cas.mdr.nims.test + ``` + +2. In your `.env` file, set the following variables: + + ``` + MDR_DEVISE_AUTH_MODULE=cas_authenticatable + CAS_BASE_URL=https://cas.mdr.nims.test:8443/cas/ + ``` + +3. Now build and run the `web` and `cas` containers: + + ```bash + docker-compose build web cas + docker-compose up web cas + ``` + +4. Open a browser and goto the MDR website: http://mdr.nims.test:3000/ + Click on Login and you should be directed to https://cas.mdr.nims.test:8443/cas/ + + At this point your web browser will likely complain that the SSL certificate is invalid / untrusted. Grant the + certificate `cas.mdr.nims.test` full trust: + + * In Chrome, view the certificate and export it (or drag it) to your desktop + * Next, double-click on the certificate file (`cas.mdr.nims.test.cer`) and mark it as Always Trust (see: https://support.apple.com/en-gb/guide/keychain-access/kyca11871/mac) + * Check that reloading https://cas.mdr.nims.test:8443/cas/ should now present the valid CAS website without any certificate warnings or other errors + +5. To test single sign-on, open a browser window and go to to the MDR website: http://mdr.nims.test:3000/ + + * Click on "login" and you will be redirected to the CAS website. + * Log in as `user1` / `password`. + * After completing the login on the CAS website you will be redirected back to the MDR website and now logged in as `user1` + +6. To test single sign-off, after logging in as `user1` on MDR (see previous step), open an extra browser window and navigate directly to the CAS website: https://cas.mdr.nims.test:8443/cas + + * Logout of the CAS system (by clicking on "log out" in "please log out and exit your web browser") + * Then reload the *other* browser window which had the user logged in to MDR and verify that they are now logged out. + +## Backups + +There is [docker documentation](https://docs.docker.com/storage/volumes/#backup-restore-or-migrate-data-volumes) advising how to back up volumes and their data. + +### System initialisation and configuration + +* As mentioned above, there is a `.env` file containing application secrets. This **must not** be checked into version control! +* The system is configured on start-up using the `docker-entrypoint.sh` script, which configures users in the `seed/setup.json` file. +* Importers are run manually in the container using the rails console. See [The project wiki](https://github.com/antleaf/nims-hyrax/wiki) for more information. + +## Code Status + +[![Codeship Status for antleaf/nims-hyrax](https://app.codeship.com/projects/d4cc8560-e430-0136-fffd-6a7889452552/status?branch=develop)](https://app.codeship.com/projects/319029) + +[![Coverage Status](https://coveralls.io/repos/github/antleaf/nims-hyrax/badge.svg?branch=develop)](https://coveralls.io/github/antleaf/nims-hyrax?branch=develop) diff --git a/cas/.mvn/.keep b/cas/.mvn/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cas/Dockerfile b/cas/Dockerfile new file mode 100644 index 00000000..8e31a121 --- /dev/null +++ b/cas/Dockerfile @@ -0,0 +1,15 @@ +FROM apereo/cas:v5.3.10 +COPY pom.xml /cas-overlay/ +COPY .mvn/ /cas-overlay/.mvn/ +RUN build.sh package + +RUN keytool -genkeypair -alias cas -keyalg RSA -keypass changeit \ + -storepass changeit -keystore /cas-overlay/etc/cas/thekeystore \ + -dname "CN=cas.mdr.nims.test,OU=MDR,OU=NIMS,OU=Test,C=JP" \ + -ext SAN="dns:cas.mdr.nims.test,dns:localhost,ip:127.0.0.1" \ + -validity 365 +COPY etc/cas/config/* /cas-overlay/etc/cas/config/ +COPY etc/cas/services/* /cas-overlay/etc/cas/services/ +COPY etc/cas/users.json /cas-overlay/etc/cas/ +COPY pom.xml /cas-overlay/ +RUN build.sh copy diff --git a/cas/etc/cas/config/cas.properties b/cas/etc/cas/config/cas.properties new file mode 100644 index 00000000..e2ced10c --- /dev/null +++ b/cas/etc/cas/config/cas.properties @@ -0,0 +1,22 @@ +# Required CAS settings +cas.server.name: https://cas.mdr.nims.test:8443 +cas.server.prefix: https://cas.mdr.nims.test:8443/cas + +cas.httpWebRequest.header.hsts=false +cas.adminPagesSecurity.ip=127\.0\.0\.1 +cas.logout.followServiceRedirects=true +cas.logout.redirectParameter=service + +logging.config: file:/etc/cas/config/log4j2.xml + +# Service Registry +cas.serviceRegistry.initFromJson: false +cas.serviceRegistry.json.location: file:/etc/cas/services + +# Disable authentication with a static list of credentials +cas.authn.accept.users= + +# Use JSON file for authentication +cas.authn.json.location=file:///etc/cas/users.json +cas.authn.json.name= +# cas.authn.json.passwordPolicy= diff --git a/cas/etc/cas/config/log4j2.xml b/cas/etc/cas/config/log4j2.xml new file mode 100644 index 00000000..36a22845 --- /dev/null +++ b/cas/etc/cas/config/log4j2.xml @@ -0,0 +1,117 @@ + + + + + + . + + debug + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cas/etc/cas/services/casmdrnimstest-1.json b/cas/etc/cas/services/casmdrnimstest-1.json new file mode 100644 index 00000000..2a88c349 --- /dev/null +++ b/cas/etc/cas/services/casmdrnimstest-1.json @@ -0,0 +1,8 @@ +{ + "@class" : "org.apereo.cas.services.RegexRegisteredService", + "serviceId" : "^(https|http)://.*", + "name" : "cas.mdr.nims.test", + "id" : 1, + "logoutType" : "BACK_CHANNEL", + "logoutUrl" : "http://mdr.nims.test:3000/users/service" +} diff --git a/cas/etc/cas/users.json b/cas/etc/cas/users.json new file mode 100644 index 00000000..45a1ec2c --- /dev/null +++ b/cas/etc/cas/users.json @@ -0,0 +1,14 @@ +{ + "@class" : "java.util.LinkedHashMap", + "user1" : { + "@class" : "org.apereo.cas.adaptors.generic.CasUserAccount", + "password" : "password", + "attributes" : { + "@class" : "java.util.LinkedHashMap", + "firstName" : "Apereo", + "lastName" : "CAS" + }, + "status" : "OK", + "expirationDate" : "2022-01-19" + } +} diff --git a/cas/pom.xml b/cas/pom.xml new file mode 100644 index 00000000..867a86be --- /dev/null +++ b/cas/pom.xml @@ -0,0 +1,230 @@ + + + 4.0.0 + org.apereo.cas + cas-overlay + war + 1.0 + + + + + com.rimerosolutions.maven.plugins + wrapper-maven-plugin + 0.0.5 + + true + MD5 + + + + org.springframework.boot + spring-boot-maven-plugin + ${springboot.version} + + ${mainClassName} + true + ${isExecutable} + WAR + + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 2.6 + + cas + false + false + + false + ${manifestFileToUse} + + + + org.apereo.cas + cas-server-webapp${app.server} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + + cas + + + + + org.apereo.cas + cas-server-support-json-service-registry + ${cas.version} + + + org.apereo.cas + cas-server-support-generic + ${cas.version} + + + + + 5.3.9 + 1.5.18.RELEASE + + -tomcat + + org.springframework.boot.loader.WarLauncher + false + + ${project.build.directory}/war/work/org.apereo.cas/cas-server-webapp${app.server}/META-INF/MANIFEST.MF + + + 1.8 + 1.8 + UTF-8 + + + + + sonatype-releases + http://oss.sonatype.org/content/repositories/releases/ + + false + + + true + + + + sonatype-snapshots + https://oss.sonatype.org/content/repositories/snapshots/ + + true + + + false + + + + shibboleth-releases + https://build.shibboleth.net/nexus/content/repositories/releases + + + + + + + true + + default + + + org.apereo.cas + cas-server-webapp${app.server} + ${cas.version} + war + runtime + + + + + + + + false + + exec + + org.apereo.cas.web.CasWebApplication + true + + + + + + com.soebes.maven.plugins + echo-maven-plugin + 0.3.0 + + + prepare-package + + echo + + + + + + Executable profile to make the generated CAS web application executable. + + + + + + + + + + false + + bootiful + + -tomcat + false + + + + org.apereo.cas + cas-server-webapp${app.server} + ${cas.version} + war + runtime + + + + + + + false + + pgp + + + + com.github.s4u.plugins + pgpverify-maven-plugin + 1.1.0 + + + + check + + + + + hkp://pool.sks-keyservers.net + ${settings.localRepository}/pgpkeys-cache + test + true + false + + + + + + + diff --git a/docker-compose-production.yml b/docker-compose-production.yml new file mode 100644 index 00000000..f659dcfe --- /dev/null +++ b/docker-compose-production.yml @@ -0,0 +1,9 @@ +# Overrides the docker-compose file for production environment +# - app accessible on port 3000 + +version: '3' + +services: + web: + ports: + - 3000:3000 \ No newline at end of file diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 00000000..4edb97b8 --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,64 @@ +# Overrides the docker-compose file for development environment +# - Use the example end.production file (because in dev it doesn't matter) +# - Publish the fcrepo and solr ports +# - No nginx in front of the app +# - app accessible on port 3000 + +# todo: nginx to serve static files + +version: '3' + +volumes: + file_uploads: + derivatives: + cache: + fcrepo: + redis: + +services: + + fcrepo: + ports: + - 8080:8080 + volumes: + - fcrepo:/data + + solr: + ports: + - 8983:8983 + + app: + volumes: + - file_uploads:${UPLOADS_PATH} + - derivatives:${DERIVATIVES_PATH} + - cache:${CACHE_PATH} + - ${HOST_APP_DATA_PATH:-/srv/ngdr/data/}:/data/data + + web: + ports: + - 3000:3000 + depends_on: + - cas + environment: + - RAILS_FORCE_SSL=false + networks: + internal: + aliases: + - web + - mdr.nims.test + + redis: + volumes: + - redis:/data + + cas: + build: + context: cas + networks: + internal: + aliases: + - cas + - cas.mdr.nims.test + + ports: + - 8443:8443 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..243ec279 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,136 @@ +version: '3' + +volumes: + solr: + db: + db-fcrepo: + app: + +networks: + internal: + +services: + fcrepo: + image: ualbertalib/docker-fcrepo4:4.7 + expose: + - 8080 + depends_on: + - fcrepodb + networks: + internal: + environment: + - CATALINA_OPTS=-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms512m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DisableExplicitGC -Dfcrepo.home=/data -Dfcrepo.object.directory=/data/objects -Dfcrepo.binary.directory=/data/binaries -Dfcrepo.postgresql.username=$POSTGRES_USER -Dfcrepo.postgresql.password=$POSTGRES_PASSWORD -Dfcrepo.postgresql.host=$POSTGRES_HOST_FCREPO -Dfcrepo.postgresql.port=$POSTGRES_PORT -Dfcrepo.modeshape.configuration=classpath:/config/jdbc-postgresql/repository.json + + solr: + image: solr:7-alpine + expose: + - 8983 + ports: + - 8983:8983 + env_file: + - .env + healthcheck: + test: ["CMD-SHELL", "wget -O /dev/null http://localhost:8983/solr/"] + interval: 30s + timeout: 5s + retries: 3 + networks: + internal: + volumes: + - solr:/opt/solr/server/solr/mycores + - ./hyrax/solr/config:/opt/solr/solr_conf + entrypoint: + - docker-entrypoint.sh + - solr-precreate + - ${SOLR_CORE} + - /opt/solr/solr_conf + + db: &db + image: postgres:11-alpine + networks: + internal: + env_file: + - .env + expose: + - 5432 + fcrepodb: + <<: *db + environment: + - POSTGRES_DB=${POSTGRES_DB_FCREPO} + volumes: + - db-fcrepo:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "POSTGRES_PASSWORD=${POSTGRES_PASSWORD} pg_isready -U ${POSTGRES_USER} -h localhost -d ${POSTGRES_DB_FCREPO}"] + interval: 30s + timeout: 5s + retries: 3 + appdb: + <<: *db + environment: + - POSTGRES_DB=${POSTGRES_DB_APP} + volumes: + - db:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "POSTGRES_PASSWORD=${POSTGRES_PASSWORD} pg_isready -U ${POSTGRES_USER} -h localhost -d ${POSTGRES_DB_APP}"] + interval: 30s + timeout: 5s + retries: 3 + + app: &app + build: + context: hyrax + args: + RAILS_ENV: ${RAILS_ENV} + UPLOADS_PATH: ${UPLOADS_PATH} + DERIVATIVES_PATH: ${DERIVATIVES_PATH} + CACHE_PATH: ${CACHE_PATH} + FITS_PATH: ${FITS_PATH} + FITS_VERSION: ${FITS_VERSION} + AIRBRAKE_HOST: ${AIRBRAKE_HOST} + AIRBRAKE_PROJECT_ID: ${AIRBRAKE_PROJECT_ID} + AIRBRAKE_PROJECT_KEY: ${AIRBRAKE_PROJECT_KEY} + env_file: + - .env + volumes: + - app:${UPLOADS_PATH} + - app:${DERIVATIVES_PATH} + - app:${CACHE_PATH} + - app:${BRAND_PATH} + networks: + internal: + + web: + <<: *app + command: bash -c "/bin/docker-entrypoint.sh" + environment: + - VIRTUAL_HOST=nims.docker + - VIRTUAL_PORT=3000 + depends_on: + - appdb + - solr + - fcrepo + - redis + expose: + - 3000 + + workers: + <<: *app + command: bundle exec sidekiq + depends_on: + - appdb + - solr + - fcrepo + - redis + + redis: + image: redis:5 + command: redis-server --appendonly yes + expose: + - 6379 + networks: + internal: + healthcheck: + test: ["CMD-SHELL", "redis-cli ping"] + interval: 30s + timeout: 5s + retries: 3 diff --git a/hyrax/.ruby-version b/hyrax/.ruby-version new file mode 100644 index 00000000..aedc15bb --- /dev/null +++ b/hyrax/.ruby-version @@ -0,0 +1 @@ +2.5.3 diff --git a/hyrax/.solr_wrapper.yml b/hyrax/.solr_wrapper.yml deleted file mode 100644 index 53894b72..00000000 --- a/hyrax/.solr_wrapper.yml +++ /dev/null @@ -1,5 +0,0 @@ -# Place any default configuration for solr_wrapper here -# port: 8983 -collection: - dir: solr/conf/ - name: blacklight-core diff --git a/hyrax/Dockerfile b/hyrax/Dockerfile new file mode 100644 index 00000000..b6572ade --- /dev/null +++ b/hyrax/Dockerfile @@ -0,0 +1,94 @@ +FROM ruby:2.6 + +# Setup build variables +ARG RAILS_ENV +ARG DERIVATIVES_PATH +ARG UPLOADS_PATH +ARG CACHE_PATH +ARG AIRBRAKE_HOST +ARG AIRBRAKE_PROJECT_ID +ARG AIRBRAKE_PROJECT_KEY +ARG FITS_PATH +ARG FITS_VERSION + +ENV APP_PRODUCTION=/data/ \ + APP_WORKDIR=/data + +# Add backports to apt-get sources +# Install libraries, dependencies, java and fits + +RUN echo 'deb http://deb.debian.org/debian buster main contrib non-free' +RUN echo 'deb-src http://deb.debian.org/debian buster main contrib non-free' + +RUN apt-get update -qq && \ + apt-get -y install apt-transport-https && \ + curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ + echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ + curl -sL https://deb.nodesource.com/setup_8.x | bash - && \ + apt-get update -qq && apt-get install -y --no-install-recommends \ + libpq-dev \ + libxml2-dev libxslt1-dev \ + nodejs \ + libreoffice \ + libass-dev libfreetype6-dev libmp3lame-dev libopus-dev libsdl2-dev libtheora-dev libtool libva-dev libvdpau-dev \ + libvpx-dev libvorbis-dev libx264-dev libx265-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev nasm pkg-config \ + texinfo wget yasm zlib1g-dev fonts-ipaexfont fonts-ipafont fonts-vlgothic \ + libjpeg-dev libtiff-dev libpng-dev libraw-dev libwebp-dev libjxr-dev \ + libcairo2-dev libgs-dev librsvg2-dev \ + libmp3lame-dev libvorbis-dev libtheora-dev libspeex-dev libx264-dev \ + ghostscript ffmpeg imagemagick \ + ufraw \ + bzip2 unzip xz-utils \ + vim \ + git \ + openjdk-11-jre-headless \ + yarn && \ + yarn config set no-progress && \ + yarn config set silent + +RUN mkdir -p /fits/ \ + && wget -q https://projects.iq.harvard.edu/files/fits/files/$FITS_VERSION.zip -O /fits/$FITS_VERSION.zip \ + && unzip -q /fits/$FITS_VERSION.zip -d /fits/$FITS_VERSION \ + && chmod a+x $FITS_PATH \ + && rm /fits/$FITS_VERSION.zip + +# copy gemfiles to production folder +COPY Gemfile Gemfile.lock $APP_PRODUCTION + +# install gems to system - use flags dependent on RAILS_ENV +RUN cd $APP_PRODUCTION && \ + bundle config build.nokogiri --use-system-libraries \ + && if [ "$RAILS_ENV" = "production" ]; then \ + bundle install --without test:development; \ + else \ + bundle install --without production --no-deployment; \ + fi \ + && mv Gemfile.lock Gemfile.lock.built_by_docker + +# copy the seeds +COPY ./seed /seed + +# create a folder to store derivatives, file uploads and cache directory +RUN mkdir -p $DERIVATIVES_PATH +RUN mkdir -p $UPLOADS_PATH +RUN mkdir -p $CACHE_PATH + +# copy the application +COPY . $APP_PRODUCTION +COPY docker-entrypoint.sh /bin/ + +# use the just built Gemfile.lock, not the one copied into the container and verify the gems are correctly installed +RUN cd $APP_PRODUCTION \ + && mv Gemfile.lock.built_by_docker Gemfile.lock \ + && bundle check + +# generate production assets if production environment +RUN if [ "$RAILS_ENV" = "production" ]; then \ + cd $APP_PRODUCTION \ + && yarn install \ + && SECRET_KEY_BASE_PRODUCTION=0 bundle exec rake assets:clean assets:precompile; \ + fi + +WORKDIR $APP_WORKDIR + +RUN chmod +x /bin/docker-entrypoint.sh diff --git a/hyrax/Gemfile b/hyrax/Gemfile index af45d15f..dc8a4cfd 100644 --- a/hyrax/Gemfile +++ b/hyrax/Gemfile @@ -8,10 +8,8 @@ end # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '>= 5.0.6' -# Use sqlite3 as the database for Active Record -gem 'sqlite3' # Use Puma as the app server -gem 'puma', '~> 3.0' +gem 'puma', '~> 3.12' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets @@ -29,6 +27,9 @@ gem 'turbolinks', '~> 5' gem 'jbuilder', '~> 2.5' # Use Redis adapter to run Action Cable in production gem 'redis', '~> 3.0' +# Using redis to store sessions in the redis cache (rather than cookies) - this is to support single sign out +# NB: Once we upgrade to rails >= 5.2 the gem can probably be removed as redis sessions are built in +gem 'redis-session-store', '~> 0.11.1' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' @@ -38,6 +39,7 @@ gem 'redis', '~> 3.0' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platform: :mri + gem 'factory_bot_rails' end group :development do @@ -52,7 +54,7 @@ end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] -gem 'hyrax', '~> 2.3.0' +gem 'hyrax', '~> 2.6' group :development, :test do gem 'solr_wrapper', '~> 2.0' end @@ -61,10 +63,39 @@ gem 'rsolr', '>= 1.0' gem 'devise' gem 'devise-guests', '~> 0.6' group :development, :test do + # Use sqlite3 as the database for Active Record + gem 'sqlite3', '~> 1.3.6' gem 'fcrepo_wrapper' gem 'rspec-rails' + gem 'pry' end -gem 'riiif', '~> 1.1' gem 'sidekiq' gem 'hydra-role-management' +gem 'bootstrap-datepicker-rails' +gem 'pg' +gem 'faraday_middleware' +gem 'devise_ldap_authenticatable' +gem 'devise_cas_authenticatable' + +gem 'cancancan', '~> 1.17' # NB: locked to an older version because of hyrax > hydra-editor + +gem 'riiif', '~> 2.0' + +group :production do + gem 'airbrake', '~> 5.0' +end + +gem 'willow_sword', git: 'https://github.com/CottageLabs/willow_sword.git', :branch => 'feature/prep_for_new_release' +gem 'blacklight_oai_provider', git: 'https://github.com/CottageLabs/blacklight_oai_provider.git', branch: 'master' + +group :test do + gem 'simplecov', require: false + gem 'capybara' + gem 'launchy' + gem 'webdrivers', '~> 4.1' + gem 'cucumber-rails', :require => false + gem 'database_cleaner' +end + +gem 'coveralls', require: false diff --git a/hyrax/Gemfile.lock b/hyrax/Gemfile.lock index d0055941..a3096e6a 100644 --- a/hyrax/Gemfile.lock +++ b/hyrax/Gemfile.lock @@ -1,25 +1,46 @@ +GIT + remote: https://github.com/CottageLabs/blacklight_oai_provider.git + revision: 73d5f34315e313fb22084cfc52939d71e3c0728a + branch: master + specs: + blacklight_oai_provider (1.4.1) + blacklight (>= 6.1) + oai (~> 0.4.0) + rails (>= 4.2) + +GIT + remote: https://github.com/CottageLabs/willow_sword.git + revision: ab456d99eaa4d07ed12d0510330be07909981204 + branch: feature/prep_for_new_release + specs: + willow_sword (0.2.0) + bagit (~> 0.4.1) + libxml-ruby (~> 3.1.0) + rails (~> 5.1.6.1) + rubyzip (>= 1.0.0) + GEM remote: https://rubygems.org/ specs: - actioncable (5.1.6) - actionpack (= 5.1.6) + actioncable (5.1.6.2) + actionpack (= 5.1.6.2) nio4r (~> 2.0) websocket-driver (~> 0.6.1) - actionmailer (5.1.6) - actionpack (= 5.1.6) - actionview (= 5.1.6) - activejob (= 5.1.6) + actionmailer (5.1.6.2) + actionpack (= 5.1.6.2) + actionview (= 5.1.6.2) + activejob (= 5.1.6.2) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.1.6) - actionview (= 5.1.6) - activesupport (= 5.1.6) + actionpack (5.1.6.2) + actionview (= 5.1.6.2) + activesupport (= 5.1.6.2) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.1.6) - activesupport (= 5.1.6) + actionview (5.1.6.2) + activesupport (= 5.1.6.2) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -40,61 +61,69 @@ GEM activesupport (>= 3.0.0) rdf (>= 2.0.2, < 4.0) rdf-vocab (>= 2.0, < 4.0) - active_encode (0.4.1) + active_encode (0.6.0) rails - activejob (5.1.6) - activesupport (= 5.1.6) + activejob (5.1.6.2) + activesupport (= 5.1.6.2) globalid (>= 0.3.6) - activemodel (5.1.6) - activesupport (= 5.1.6) - activerecord (5.1.6) - activemodel (= 5.1.6) - activesupport (= 5.1.6) + activemodel (5.1.6.2) + activesupport (= 5.1.6.2) + activerecord (5.1.6.2) + activemodel (= 5.1.6.2) + activesupport (= 5.1.6.2) arel (~> 8.0) - activerecord-import (0.27.0) + activerecord-import (1.0.3) activerecord (>= 3.2) - activesupport (5.1.6) + activesupport (5.1.6.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.5.2) - public_suffix (>= 2.0.2, < 4.0) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + airbrake (5.8.1) + airbrake-ruby (~> 1.8) + airbrake-ruby (1.8.0) almond-rails (0.1.0) rails (>= 4.2, < 6) arel (8.0.0) - autoprefixer-rails (8.6.5) + autoprefixer-rails (9.6.0) execjs - awesome_nested_set (3.1.4) - activerecord (>= 4.0.0, < 5.3) - aws-eventstream (1.0.1) - aws-partitions (1.107.0) - aws-sdk-core (3.36.0) - aws-eventstream (~> 1.0) - aws-partitions (~> 1.0) - aws-sigv4 (~> 1.0) + awesome_nested_set (3.2.0) + activerecord (>= 4.0.0, < 7.0) + aws-eventstream (1.0.3) + aws-partitions (1.230.0) + aws-sdk-core (3.72.0) + aws-eventstream (~> 1.0, >= 1.0.2) + aws-partitions (~> 1, >= 1.228.0) + aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.11.0) - aws-sdk-core (~> 3, >= 3.26.0) - aws-sigv4 (~> 1.0) - aws-sdk-s3 (1.23.1) - aws-sdk-core (~> 3, >= 3.26.0) + aws-sdk-kms (1.25.0) + aws-sdk-core (~> 3, >= 3.71.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.52.0) + aws-sdk-core (~> 3, >= 3.71.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.0) - aws-sigv4 (1.0.3) + aws-sigv4 (~> 1.1) + aws-sigv4 (1.1.0) + aws-eventstream (~> 1.0, >= 1.0.2) babel-source (5.8.35) babel-transpiler (0.7.0) babel-source (>= 4.0, < 6) execjs (~> 2.0) + backports (3.15.0) + bagit (0.4.3) + docopt (~> 0.5.0) + validatable (~> 1.6) bcp47 (0.3.3) i18n - bcrypt (3.1.11) - bindex (0.5.0) - blacklight (6.15.0) + bcrypt (3.1.13) + bindex (0.7.0) + blacklight (6.20.0) bootstrap-sass (~> 3.2) deprecation globalid - jbuilder + jbuilder (~> 2.7) kaminari (>= 0.15) nokogiri (~> 1.6) rails (>= 4.2, < 6) @@ -104,37 +133,50 @@ GEM blacklight (~> 6.0) cancancan (~> 1.8) deprecation (~> 1.0) - blacklight-gallery (0.11.0) + blacklight-gallery (0.12.0) blacklight (~> 6.3) bootstrap-sass (~> 3.0) openseadragon (>= 0.2.0) rails - bootstrap-sass (3.3.7) + bootstrap-datepicker-rails (1.8.0.1) + railties (>= 3.0) + bootstrap-sass (3.4.1) autoprefixer-rails (>= 5.2.1) - sass (>= 3.3.4) - bootstrap_form (2.7.0) + sassc (>= 2.0.0) + bootstrap_form (4.2.0) + actionpack (>= 5.0) + activemodel (>= 5.0) breadcrumbs_on_rails (3.0.1) - browse-everything (0.15.1) + browse-everything (1.0.1) addressable (~> 2.5) aws-sdk-s3 - bootstrap-sass (~> 3.2) dropbox_api (>= 0.1.10) - font-awesome-rails - google-api-client (~> 0.9) - google_drive - httparty - rails (>= 3.1) + google-api-client (~> 0.23) + google_drive (~> 2.1) + googleauth (= 0.6.6) + rails (>= 4.2) ruby-box - sass-rails - signet + signet (~> 0.8) + thor (~> 0.19) + typhoeus builder (3.2.3) - byebug (10.0.2) + byebug (11.0.1) cancancan (1.17.0) - carrierwave (1.2.3) + capybara (3.29.0) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (~> 1.5) + xpath (~> 3.2) + carrierwave (1.3.1) activemodel (>= 4.0.0) activesupport (>= 4.0.0) mime-types (>= 1.16) + childprocess (3.0.0) clipboard-rails (1.7.1) + coderay (1.1.2) coffee-rails (4.2.2) coffee-script (>= 2.2.0) railties (>= 4.0.0) @@ -142,85 +184,149 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.0.5) + concurrent-ruby (1.1.5) connection_pool (2.2.2) - crass (1.0.4) - daemons (1.2.6) + coveralls (0.7.1) + multi_json (~> 1.3) + rest-client + simplecov (>= 0.7) + term-ansicolor + thor + crass (1.0.5) + cucumber (3.1.2) + builder (>= 2.1.2) + cucumber-core (~> 3.2.0) + cucumber-expressions (~> 6.0.1) + cucumber-wire (~> 0.0.1) + diff-lcs (~> 1.3) + gherkin (~> 5.1.0) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.2) + cucumber-core (3.2.1) + backports (>= 3.8.0) + cucumber-tag_expressions (~> 1.1.0) + gherkin (~> 5.0) + cucumber-expressions (6.0.1) + cucumber-rails (1.8.0) + capybara (>= 2.12, < 4) + cucumber (>= 3.0.2, < 4) + mime-types (>= 2.0, < 4) + nokogiri (~> 1.8) + railties (>= 4.2, < 7) + cucumber-tag_expressions (1.1.1) + cucumber-wire (0.0.1) + database_cleaner (1.7.0) declarative (0.0.10) declarative-option (0.1.0) deprecation (1.0.0) activesupport - devise (4.4.3) + devise (4.7.1) bcrypt (~> 3.0) orm_adapter (~> 0.1) - railties (>= 4.1.0, < 6.0) + railties (>= 4.1.0) responders warden (~> 1.2.3) - devise-guests (0.6.0) + devise-guests (0.7.0) devise + devise_cas_authenticatable (1.10.4) + devise (>= 1.2.0) + rubycas-client (>= 2.2.1) + devise_ldap_authenticatable (0.8.6) + devise (>= 3.4.1) + net-ldap (>= 0.16.0) diff-lcs (1.3) - dropbox_api (0.1.12) - faraday (~> 0.9, ~> 0.8) + docile (1.3.2) + docopt (0.5.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dropbox_api (0.1.17) + faraday (>= 0.8, <= 0.15.4) oauth2 (~> 1.1) - dry-configurable (0.7.0) + dry-configurable (0.8.3) concurrent-ruby (~> 1.0) - dry-container (0.6.0) + dry-core (~> 0.4, >= 0.4.7) + dry-container (0.7.2) concurrent-ruby (~> 1.0) dry-configurable (~> 0.1, >= 0.1.3) - dry-core (0.4.7) + dry-core (0.4.9) + concurrent-ruby (~> 1.0) + dry-equalizer (0.2.2) + dry-events (0.2.0) + concurrent-ruby (~> 1.0) + dry-core (~> 0.4) + dry-equalizer (~> 0.2) + dry-inflector (0.2.0) + dry-logic (0.6.1) concurrent-ruby (~> 1.0) - dry-equalizer (0.2.1) - dry-inflector (0.1.2) - dry-logic (0.4.2) - dry-container (~> 0.2, >= 0.2.6) dry-core (~> 0.2) dry-equalizer (~> 0.2) + dry-matcher (0.8.2) + dry-core (>= 0.4.8) + dry-monads (1.3.1) + concurrent-ruby (~> 1.0) + dry-core (~> 0.4, >= 0.4.4) + dry-equalizer dry-struct (0.6.0) dry-core (~> 0.4, >= 0.4.3) dry-equalizer (~> 0.2) dry-types (~> 0.13) ice_nine (~> 0.11) - dry-types (0.13.2) + dry-transaction (0.13.0) + dry-container (>= 0.2.8) + dry-events (>= 0.1.0) + dry-matcher (>= 0.7.0) + dry-monads (>= 0.4.0) + dry-types (0.14.1) concurrent-ruby (~> 1.0) dry-container (~> 0.3) dry-core (~> 0.4, >= 0.4.4) dry-equalizer (~> 0.2) dry-inflector (~> 0.1, >= 0.1.2) - dry-logic (~> 0.4, >= 0.4.2) - dry-validation (0.12.2) + dry-logic (~> 0.5, >= 0.5) + dry-validation (0.13.3) concurrent-ruby (~> 1.0) dry-configurable (~> 0.1, >= 0.1.3) dry-core (~> 0.2, >= 0.2.1) dry-equalizer (~> 0.2) - dry-logic (~> 0.4, >= 0.4.0) - dry-types (~> 0.13.1) + dry-logic (~> 0.5, >= 0.5.0) + dry-types (~> 0.14.0) ebnf (1.1.3) rdf (~> 3.0) sxp (~> 1.0) equivalent-xml (0.6.0) nokogiri (>= 1.4.3) - erubi (1.7.1) + erubi (1.9.0) + ethon (0.12.0) + ffi (>= 1.3.0) execjs (2.7.0) + factory_bot (5.0.2) + activesupport (>= 4.2.0) + factory_bot_rails (5.0.2) + factory_bot (~> 5.0.2) + railties (>= 4.2.0) faraday (0.12.2) multipart-post (>= 1.2, < 3) faraday-encoding (0.0.4) faraday + faraday_middleware (0.13.1) + faraday (>= 0.7.4, < 1.0) fcrepo_wrapper (0.9.0) ruby-progressbar - ffi (1.9.25) - flipflop (2.4.0) + ffi (1.11.1) + flipflop (2.6.0) activesupport (>= 4.0) flot-rails (0.0.7) jquery-rails - font-awesome-rails (4.7.0.4) - railties (>= 3.2, < 6.0) - globalid (0.4.1) + font-awesome-rails (4.7.0.5) + railties (>= 3.2, < 6.1) + gherkin (5.1.0) + globalid (0.4.2) activesupport (>= 4.2.0) - google-api-client (0.24.3) + google-api-client (0.32.1) addressable (~> 2.5, >= 2.5.1) - googleauth (>= 0.5, < 0.7.0) + googleauth (>= 0.5, < 0.10.0) httpclient (>= 2.8.1, < 3.0) - mime-types (~> 3.0) + mini_mime (~> 1.0) representable (~> 3.0) retriable (>= 2.0, < 4.0) signet (~> 0.10) @@ -228,88 +334,91 @@ GEM google-api-client (>= 0.11.0, < 1.0.0) googleauth (>= 0.5.0, < 1.0.0) nokogiri (>= 1.5.3, < 2.0.0) - googleauth (0.6.7) + googleauth (0.6.6) faraday (~> 0.12) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) + memoist (~> 0.12) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (~> 0.7) - haml (5.0.4) + haml (5.1.2) temple (>= 0.8.0) tilt hamster (3.0.0) concurrent-ruby (~> 1.0) - hiredis (0.6.1) + hiredis (0.6.3) htmlentities (4.3.4) + http-accept (1.7.0) + http-cookie (1.0.3) + domain_name (~> 0.5) http_logger (0.5.1) - httparty (0.16.2) - multi_xml (>= 0.5.2) httpclient (2.8.3) - hydra-access-controls (10.6.0) - active-fedora (>= 10.0.0, < 13) + hydra-access-controls (10.7.0) + active-fedora (>= 10.0.0) activesupport (>= 4, < 6) blacklight (>= 5.16) blacklight-access_controls (~> 0.6.0) cancancan (~> 1.8) deprecation (~> 1.0) - hydra-core (10.6.0) - hydra-access-controls (= 10.6.0) + hydra-core (10.7.0) + hydra-access-controls (= 10.7.0) railties (>= 4.0.0, < 6) - hydra-derivatives (3.4.1) - active-fedora (>= 11.3.1, < 13) + hydra-derivatives (3.5.0) + active-fedora (>= 11.3.1, < 14) active_encode (~> 0.1) activesupport (>= 4.0, < 6) addressable (~> 2.5) deprecation mime-types (> 2.0, < 4.0) mini_magick (>= 3.2, < 5) - hydra-editor (4.0.2) + hydra-editor (5.0.1) active-fedora (>= 9.0.0) + activerecord (~> 5.0) almond-rails (~> 0.1) cancancan (~> 1.8) - rails (>= 4.2.0, < 6) - simple_form (~> 3.2) + rails (>= 5, < 6) + simple_form (>= 4.1.0, < 6.0) + sprockets (~> 3.7) sprockets-es6 - hydra-file_characterization (0.3.3) + thor (~> 0.19) + hydra-file_characterization (1.1.0) activesupport (>= 3.0.0) - hydra-head (10.6.0) - hydra-access-controls (= 10.6.0) - hydra-core (= 10.6.0) + hydra-head (10.7.0) + hydra-access-controls (= 10.7.0) + hydra-core (= 10.7.0) rails (>= 3.2.6) - hydra-pcdm (1.0.0) - active-fedora (>= 10, < 13) - activesupport (< 5.2) + hydra-pcdm (1.1.0) + active-fedora (>= 10, < 14) mime-types (>= 1) hydra-role-management (1.0.0) blacklight bootstrap_form cancancan - hydra-works (1.0.0) - activesupport (>= 4.2.10, < 5.2) + hydra-works (1.2.0) + activesupport (>= 4.2.10, < 6.0) hydra-derivatives (~> 3.0) - hydra-file_characterization (~> 0.3, >= 0.3.3) + hydra-file_characterization (~> 1.0) hydra-pcdm (>= 0.9) - om (~> 3.1) - hyrax (2.3.3) + hyrax (2.6.0) active-fedora (~> 11.5, >= 11.5.2) almond-rails (~> 0.1) awesome_nested_set (~> 3.1) blacklight (~> 6.14) blacklight-gallery (~> 0.7) breadcrumbs_on_rails (~> 3.0) - browse-everything (< 0.16) + browse-everything (>= 0.16) carrierwave (~> 1.0) clipboard-rails (~> 1.5) dry-equalizer (~> 0.2) dry-struct (~> 0.1) + dry-transaction (~> 0.11) dry-validation (~> 0.9) flipflop (~> 2.3) flot-rails (~> 0.0.6) font-awesome-rails (~> 4.2) hydra-derivatives (~> 3.3) - hydra-editor (>= 3.3, < 5.0) - hydra-head (>= 10.5.0) + hydra-editor (>= 3.3, < 6.0) + hydra-head (>= 10.6.1) hydra-works (>= 0.16, < 2.0) iiif_manifest (>= 0.3, < 0.6) jquery-datatables-rails (~> 3.4) @@ -334,18 +443,19 @@ GEM redlock (>= 0.1.2) retriable (>= 2.9, < 4.0) samvera-nesting_indexer (~> 2.0) + sass-rails (~> 5.0) select2-rails (~> 3.5) signet - simple_form (~> 3.2, <= 3.5.0) tinymce-rails (~> 4.1) - i18n (1.0.1) + i18n (1.7.0) concurrent-ruby (~> 1.0) ice_nine (0.11.2) + iiif-image-api (0.1.0) + activesupport (<= 6) iiif_manifest (0.5.0) activesupport (>= 4) - jbuilder (2.7.0) + jbuilder (2.9.1) activesupport (>= 4.2.0) - multi_json (>= 1.2) jmespath (1.4.0) jquery-datatables-rails (3.4.0) actionpack (>= 3.1) @@ -358,17 +468,17 @@ GEM thor (>= 0.14, < 2.0) jquery-ui-rails (6.0.1) railties (>= 3.2.16) - json (2.1.0) + json (2.2.0) json-ld (3.0.2) multi_json (~> 1.12) rdf (>= 2.2.8, < 4.0) - json-ld-preloaded (3.0.1) + json-ld-preloaded (3.0.6) json-ld (~> 3.0) multi_json (~> 1.12) rdf (~> 3.0) json-schema (2.8.1) addressable (>= 2.4) - jwt (2.1.0) + jwt (2.2.1) kaminari (1.1.1) activesupport (>= 4.1.0) kaminari-actionview (= 1.1.1) @@ -383,6 +493,8 @@ GEM kaminari-core (1.1.1) kaminari_route_prefix (0.1.1) kaminari (~> 1.0) + launchy (2.4.3) + addressable (~> 2.3) ld-patch (0.3.3) ebnf (~> 1.1) rdf (>= 2.2, < 4.0) @@ -401,6 +513,7 @@ GEM slop legato (0.7.0) multi_json + libxml-ruby (3.1.0) link_header (0.0.8) linkeddata (3.0.1) equivalent-xml (~> 0.6) @@ -430,102 +543,108 @@ GEM listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - loofah (2.2.2) + loofah (2.3.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) - mail (2.7.0) + mail (2.7.1) mini_mime (>= 0.1.1) mailboxer (0.15.1) carrierwave (>= 0.5.8) rails (>= 5.0.0) memoist (0.16.0) - method_source (0.9.0) - mime-types (3.2.2) + method_source (0.9.2) + mime-types (3.3) mime-types-data (~> 3.2015) - mime-types-data (3.2018.0812) - mini_magick (4.9.2) - mini_mime (1.0.0) - mini_portile2 (2.3.0) - minitest (5.11.3) - multi_json (1.13.1) + mime-types-data (3.2019.1009) + mini_magick (4.9.5) + mini_mime (1.0.2) + mini_portile2 (2.4.0) + minitest (5.13.0) + multi_json (1.14.1) + multi_test (0.1.2) multi_xml (0.6.0) - multipart-post (2.0.0) - nest (3.1.1) + multipart-post (2.1.1) + nest (3.1.2) redic - net-http-persistent (3.0.0) + net-http-persistent (3.1.0) connection_pool (~> 2.2) + net-ldap (0.16.1) + netrc (0.11.0) nio4r (2.3.1) noid (0.9.0) - noid-rails (3.0.0) + noid-rails (3.0.1) actionpack (>= 5.0.0, < 6) noid (~> 0.9) - nokogiri (1.8.4) - mini_portile2 (~> 2.3.0) + nokogiri (1.10.4) + mini_portile2 (~> 2.4.0) nokogumbo (1.5.0) nokogiri + oai (0.4.0) + builder (>= 3.1.0) + faraday + faraday_middleware oauth (0.5.4) - oauth2 (1.4.1) - faraday (>= 0.8, < 0.16.0) + oauth2 (1.4.2) + faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - om (3.1.1) - activemodel - activesupport - nokogiri (>= 1.4.2) - solrizer (~> 3.3) openseadragon (0.5.0) rails (> 3.2.0) orm_adapter (0.5.0) - os (1.0.0) + os (1.0.1) + pg (1.1.4) posix-spawn (0.3.13) power_converter (0.1.2) - public_suffix (3.0.3) + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + public_suffix (4.0.1) pul_uv_rails (2.0.1) - puma (3.11.4) - qa (2.1.2) + puma (3.12.2) + qa (2.2.0) activerecord-import deprecation faraday nokogiri (~> 1.6) rails (~> 5.0) rdf - rack (2.0.5) - rack-protection (2.0.1) + rack (2.0.7) + rack-protection (2.0.5) rack - rack-test (1.0.0) + rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.1.6) - actioncable (= 5.1.6) - actionmailer (= 5.1.6) - actionpack (= 5.1.6) - actionview (= 5.1.6) - activejob (= 5.1.6) - activemodel (= 5.1.6) - activerecord (= 5.1.6) - activesupport (= 5.1.6) + rails (5.1.6.2) + actioncable (= 5.1.6.2) + actionmailer (= 5.1.6.2) + actionpack (= 5.1.6.2) + actionview (= 5.1.6.2) + activejob (= 5.1.6.2) + activemodel (= 5.1.6.2) + activerecord (= 5.1.6.2) + activesupport (= 5.1.6.2) bundler (>= 1.3.0) - railties (= 5.1.6) + railties (= 5.1.6.2) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.0.4) - loofah (~> 2.2, >= 2.2.2) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) rails_autolink (1.1.6) rails (> 3.1) - railties (5.1.6) - actionpack (= 5.1.6) - activesupport (= 5.1.6) + railties (5.1.6.2) + actionpack (= 5.1.6.2) + activesupport (= 5.1.6.2) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rake (12.3.1) + rake (13.0.0) rb-fsevent (0.10.3) - rb-inotify (0.9.10) - ffi (>= 0.5.0, < 2) - rdf (3.0.5) + rb-inotify (0.10.0) + ffi (~> 1.0) + rdf (3.0.12) hamster (~> 3.0) link_header (~> 0.0, >= 0.0.8) rdf-aggregate-repo (2.2.1) @@ -539,8 +658,10 @@ GEM nokogiri (~> 1.8) rdf (>= 2.2.8, < 4.0) rdf-xsd (>= 2.2, < 4.0) - rdf-n3 (3.0.1) + rdf-n3 (3.1.0) rdf (~> 3.0) + sparql (~> 3.0) + sxp (~> 1.0) rdf-normalize (0.3.3) rdf (>= 2.2, < 4.0) rdf-rdfa (3.0.1) @@ -554,78 +675,90 @@ GEM rdf (>= 2.2, < 4.0) rdf-rdfa (>= 2.2, < 4.0) rdf-xsd (>= 2.2, < 4.0) - rdf-reasoner (0.5.1) + rdf-reasoner (0.5.2) rdf (~> 3.0) rdf-vocab (~> 3.0) rdf-xsd (~> 3.0) - rdf-tabular (2.2.1) + rdf-tabular (2.2.2) addressable (~> 2.3) bcp47 (~> 0.3, >= 0.3.3) json-ld (>= 2.1, < 4.0) - rdf (>= 2.2, < 4.0) - rdf-vocab (>= 2.2, < 4.0) - rdf-xsd (>= 2.2, < 4.0) + rdf (~> 3.0) + rdf-vocab (~> 3.0) + rdf-xsd (~> 3.0) rdf-trig (3.0.1) ebnf (~> 1.1) rdf (~> 3.0) rdf-turtle (~> 3.0, >= 3.0.3) rdf-trix (2.2.1) rdf (>= 2.2, < 4.0) - rdf-turtle (3.0.3) + rdf-turtle (3.0.6) ebnf (~> 1.1) rdf (~> 3.0) - rdf-vocab (3.0.3) - rdf (~> 3.0) + rdf-vocab (3.0.13) + rdf (~> 3.0, >= 3.0.11) rdf-xsd (3.0.1) rdf (~> 3.0) - redic (1.5.0) + redic (1.5.3) hiredis redis (3.3.5) redis-namespace (1.6.0) redis (>= 3.0.4) - redlock (0.2.2) + redis-session-store (0.11.1) + actionpack (>= 3) + redis (>= 3, < 5) + redlock (1.0.1) redis (>= 3.0.0, < 5.0) + regexp_parser (1.6.0) representable (3.0.4) declarative (< 0.1.0) declarative-option (< 0.2.0) uber (< 0.2.0) - responders (2.4.0) - actionpack (>= 4.2.0, < 5.3) - railties (>= 4.2.0, < 5.3) + responders (3.0.0) + actionpack (>= 5.0) + railties (>= 5.0) + rest-client (2.1.0) + http-accept (>= 1.7.0, < 2.0) + http-cookie (>= 1.0.2, < 2.0) + mime-types (>= 1.16, < 4.0) + netrc (~> 0.8) retriable (3.1.2) - riiif (1.7.0) + riiif (2.1.0) deprecation (>= 1.0.0) + iiif-image-api (~> 0.1.0) railties (>= 4.2, < 6) rsolr (2.2.1) builder (>= 2.1.2) faraday (>= 0.9.0) - rspec-core (3.7.1) - rspec-support (~> 3.7.0) - rspec-expectations (3.7.0) + rspec-core (3.8.0) + rspec-support (~> 3.8.0) + rspec-expectations (3.8.4) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.7.0) - rspec-mocks (3.7.0) + rspec-support (~> 3.8.0) + rspec-mocks (3.8.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.7.0) - rspec-rails (3.7.2) + rspec-support (~> 3.8.0) + rspec-rails (3.8.2) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 3.7.0) - rspec-expectations (~> 3.7.0) - rspec-mocks (~> 3.7.0) - rspec-support (~> 3.7.0) - rspec-support (3.7.1) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-support (~> 3.8.0) + rspec-support (3.8.2) ruby-box (1.15.0) addressable json multipart-post oauth2 - ruby-progressbar (1.9.0) - rubyzip (1.2.2) + ruby-progressbar (1.10.1) + rubycas-client (2.3.9) + activesupport + rubyzip (2.0.0) samvera-nesting_indexer (2.0.0) dry-equalizer - sass (3.5.6) + sass (3.7.4) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) @@ -636,8 +769,14 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) + sassc (2.0.1) + ffi (~> 1.9) + rake select2-rails (3.5.10) thor (~> 0.14) + selenium-webdriver (3.142.6) + childprocess (>= 0.5, < 4.0) + rubyzip (>= 1.2.2) shex (0.5.2) ebnf (~> 1.1) json-ld (>= 2.2, < 4.0) @@ -646,30 +785,33 @@ GEM rdf-xsd (>= 2.2, < 4.0) sparql (>= 2.2, < 4.0) sxp (~> 1.0) - sidekiq (5.1.3) - concurrent-ruby (~> 1.0) - connection_pool (~> 2.2, >= 2.2.0) + sidekiq (5.2.7) + connection_pool (~> 2.2, >= 2.2.2) + rack (>= 1.5.0) rack-protection (>= 1.5.0) redis (>= 3.3.5, < 5) - signet (0.11.0) + signet (0.12.0) addressable (~> 2.3) faraday (~> 0.9) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simple_form (3.5.0) - actionpack (> 4, < 5.2) - activemodel (> 4, < 5.2) - slop (4.6.2) - solr_wrapper (2.0.0) + simple_form (5.0.1) + actionpack (>= 5.0) + activemodel (>= 5.0) + simplecov (0.17.0) + docile (~> 1.1) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + slop (4.7.0) + solr_wrapper (2.1.0) faraday retriable ruby-progressbar rubyzip - solrizer (3.4.1) + solrizer (4.1.0) activesupport - daemons nokogiri - stomp xml-simple sparql (3.0.2) builder (~> 3.2) @@ -679,7 +821,7 @@ GEM rdf-xsd (~> 3.0) sparql-client (~> 3.0) sxp (~> 1.0) - sparql-client (3.0.0) + sparql-client (3.0.1) net-http-persistent (>= 2.9, < 4) rdf (~> 3.0) spring (2.0.2) @@ -699,69 +841,102 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.3.13) - stomp (1.4.5) - sxp (1.0.1) - rdf (>= 2.2, < 4.0) - temple (0.8.0) - thor (0.20.0) + sxp (1.0.2) + rdf (~> 3.0) + temple (0.8.2) + term-ansicolor (1.7.1) + tins (~> 1.0) + thor (0.20.3) thread_safe (0.3.6) - tilt (2.0.8) - tinymce-rails (4.8.4) + tilt (2.0.9) + tins (1.21.1) + tinymce-rails (4.9.6) railties (>= 3.1.1) - turbolinks (5.1.1) - turbolinks-source (~> 5.1) - turbolinks-source (5.1.0) + turbolinks (5.2.0) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) twitter-typeahead-rails (0.11.1.pre.corejavascript) actionpack (>= 3.1) jquery-rails railties (>= 3.1) + typhoeus (1.3.1) + ethon (>= 0.9.0) tzinfo (1.2.5) thread_safe (~> 0.1) uber (0.1.0) - uglifier (4.1.10) + uglifier (4.1.20) execjs (>= 0.3.0, < 3) - warden (1.2.7) - rack (>= 1.0) - web-console (3.6.2) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.6) + validatable (1.6.7) + warden (1.2.8) + rack (>= 2.0.6) + web-console (3.7.0) actionview (>= 5.0) activemodel (>= 5.0) bindex (>= 0.4.0) railties (>= 5.0) + webdrivers (4.1.3) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (>= 3.0, < 4.0) websocket-driver (0.6.5) websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.3) + websocket-extensions (0.1.4) xml-simple (1.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) PLATFORMS ruby DEPENDENCIES + airbrake (~> 5.0) + blacklight_oai_provider! + bootstrap-datepicker-rails byebug + cancancan (~> 1.17) + capybara coffee-rails (~> 4.2) + coveralls + cucumber-rails + database_cleaner devise devise-guests (~> 0.6) + devise_cas_authenticatable + devise_ldap_authenticatable + factory_bot_rails + faraday_middleware fcrepo_wrapper hydra-role-management - hyrax (~> 2.3.0) + hyrax (~> 2.6) jbuilder (~> 2.5) jquery-rails + launchy listen (~> 3.0.5) - puma (~> 3.0) + pg + pry + puma (~> 3.12) rails (>= 5.0.6) redis (~> 3.0) - riiif (~> 1.1) + redis-session-store (~> 0.11.1) + riiif (~> 2.0) rsolr (>= 1.0) rspec-rails sass-rails (~> 5.0) sidekiq + simplecov solr_wrapper (~> 2.0) spring spring-watcher-listen (~> 2.0.0) - sqlite3 + sqlite3 (~> 1.3.6) turbolinks (~> 5) tzinfo-data uglifier (>= 1.3.0) web-console (>= 3.3.0) + webdrivers (~> 4.1) + willow_sword! BUNDLED WITH - 1.16.1 + 1.17.3 diff --git a/hyrax/README.md b/hyrax/README.md index 7db80e4c..deab187f 100644 --- a/hyrax/README.md +++ b/hyrax/README.md @@ -1,24 +1,69 @@ # README +## NIMS Hyrax -This README would normally document whatever steps are necessary to get the -application up and running. +The application contains +* Hyrax version 2.3 +* Rails 5.1 -Things you may want to cover: +Requires: +* redis +* Ruby 2.3 - 2.5 -* Ruby version +### Set up ruby with `rbenv` +1. Install `rbenv` on your system per the [installation instructions](https://github.com/rbenv/rbenv#installation) +2. Get ruby 2.5.3 + ``` + rbenv install 2.5.3 + ``` +3. Install bundler + ``` + RBENV_VERSION=2.5.3 gem install bundler + ``` -* System dependencies +### Steps to install the application +1. Clone this project +2. To install, cd to the `hyrax/` directory and + ``` + bundle install + bundle exec rake db:migrate + ``` -* Configuration +### Steps to run the application +From the `hyrax/` directory: -* Database creation +* Start Solr + ``` + solr_wrapper + ``` +* Start Fedora + ``` + fcrepo_wrapper + ``` +* Start sidekiq to run the background jobs (requires a running redis instance) + ``` + bundle exec sidekiq + ``` +* Start Rails server + ``` + bundle exec rails s + ``` + +**Note:** You could use screen to run the different components +``` +screen +``` +To make it easy to navigate screen, you could add this to your ~/.screenrc file +``` +hardstatus alwayslastline "%H %-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<" +autodetach on +``` -* Database initialization +### Steps to run the tests +When the app is set up, from `hyrax/`: -* How to run the test suite + bundle exec rspec -* Services (job queues, cache servers, search engines, etc.) +for all tests, and e.g. -* Deployment instructions - -* ... + bundle exec rspec spec/models/concerns/complex_date_spec.rb +for tests in a specific file. \ No newline at end of file diff --git a/hyrax/app/actors/hyrax/actors/complex_attributes.rb b/hyrax/app/actors/hyrax/actors/complex_attributes.rb new file mode 100644 index 00000000..a10b5788 --- /dev/null +++ b/hyrax/app/actors/hyrax/actors/complex_attributes.rb @@ -0,0 +1,64 @@ +module Hyrax + module Actors + module ComplexAttributes + def apply_save_data_to_curation_concern(env) + super + # Clear this, it will be re-added by update_complex_metadata + env.curation_concern.updated_subresources = [] + env = update_complex_metadata(env, env.curation_concern) + end + + # Call execute on the ActiveTriple::Resources (ATR), like ComplexInstrument + # Due to a bug somewhere in ActiveFedora, changes to ATR + # are not being committed to the resource graph because they are BufferedTransactions + # This method runs execute on the graphs of each ATR + # Additionally adds all ATR to top-level property updates_subresources + # this seems to be necessary to get ATR nested within other ATR to update + def update_complex_metadata(env, resource_to_update) + complex_attributes.each do |attribute| + next unless resource_to_update.respond_to?(attribute) + next if resource_to_update.send(attribute).empty? + resource_to_update.send(attribute).each do |resource| + update_complex_metadata(env, resource) + resource.graph.execute + resource_to_update.send(attribute.to_s).push(resource) + env.curation_concern.updated_subresources.push(resource_to_update.send(attribute)) + end + end + env + end + + def complex_attributes + %w[ + complex_person + complex_identifier + complex_rights + complex_organization + complex_date + custom_property + complex_specimen_type + complex_version + complex_relation + complex_instrument + complex_affiliation + manufacturer + managing_organization + supplier + custom_property + complex_structural_feature + complex_state_of_matter + complex_shape + complex_purchase_record + complex_material_type + instrument_function + complex_chemical_composition + complex_crystallographic_structure + complex_event + complex_source + complex_event_date + + ] + end + end + end +end diff --git a/hyrax/app/actors/hyrax/actors/dataset_actor.rb b/hyrax/app/actors/hyrax/actors/dataset_actor.rb new file mode 100644 index 00000000..8d2d890a --- /dev/null +++ b/hyrax/app/actors/hyrax/actors/dataset_actor.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Dataset` +module Hyrax + module Actors + class DatasetActor < Hyrax::Actors::BaseActor + include Hyrax::Actors::ComplexAttributes + end + end +end diff --git a/hyrax/app/actors/hyrax/actors/image_actor.rb b/hyrax/app/actors/hyrax/actors/image_actor.rb new file mode 100644 index 00000000..6bb65a18 --- /dev/null +++ b/hyrax/app/actors/hyrax/actors/image_actor.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Image` +module Hyrax + module Actors + class ImageActor < Hyrax::Actors::BaseActor + include Hyrax::Actors::ComplexAttributes + end + end +end diff --git a/hyrax/app/actors/hyrax/actors/publication_actor.rb b/hyrax/app/actors/hyrax/actors/publication_actor.rb new file mode 100644 index 00000000..7fd47e78 --- /dev/null +++ b/hyrax/app/actors/hyrax/actors/publication_actor.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Publication` +module Hyrax + module Actors + class PublicationActor < Hyrax::Actors::BaseActor + include Hyrax::Actors::ComplexAttributes + end + end +end diff --git a/hyrax/app/actors/hyrax/actors/work_actor.rb b/hyrax/app/actors/hyrax/actors/work_actor.rb index 8690cace..fb982658 100644 --- a/hyrax/app/actors/hyrax/actors/work_actor.rb +++ b/hyrax/app/actors/hyrax/actors/work_actor.rb @@ -3,6 +3,7 @@ module Hyrax module Actors class WorkActor < Hyrax::Actors::BaseActor + include Hyrax::Actors::ComplexAttributes end end end diff --git a/hyrax/app/assets/fonts/Futura.ttc b/hyrax/app/assets/fonts/Futura.ttc new file mode 100644 index 00000000..8eaa87a0 Binary files /dev/null and b/hyrax/app/assets/fonts/Futura.ttc differ diff --git a/hyrax/app/assets/fonts/FuturaStd-Book.otf b/hyrax/app/assets/fonts/FuturaStd-Book.otf new file mode 100644 index 00000000..71e0bc02 Binary files /dev/null and b/hyrax/app/assets/fonts/FuturaStd-Book.otf differ diff --git a/hyrax/app/assets/fonts/FuturaStd-BookOblique.otf b/hyrax/app/assets/fonts/FuturaStd-BookOblique.otf new file mode 100644 index 00000000..ddb7a317 Binary files /dev/null and b/hyrax/app/assets/fonts/FuturaStd-BookOblique.otf differ diff --git a/hyrax/app/assets/fonts/GalanoGrotesqueBold.otf b/hyrax/app/assets/fonts/GalanoGrotesqueBold.otf new file mode 100644 index 00000000..9e8e153c Binary files /dev/null and b/hyrax/app/assets/fonts/GalanoGrotesqueBold.otf differ diff --git a/hyrax/app/assets/fonts/GalanoGrotesqueLight.otf b/hyrax/app/assets/fonts/GalanoGrotesqueLight.otf new file mode 100644 index 00000000..109e5c34 Binary files /dev/null and b/hyrax/app/assets/fonts/GalanoGrotesqueLight.otf differ diff --git a/hyrax/app/assets/images/MDR-linear.png b/hyrax/app/assets/images/MDR-linear.png new file mode 100644 index 00000000..9163f9ea Binary files /dev/null and b/hyrax/app/assets/images/MDR-linear.png differ diff --git a/hyrax/app/assets/images/final-icons-01-100.png b/hyrax/app/assets/images/final-icons-01-100.png new file mode 100644 index 00000000..02c767e9 Binary files /dev/null and b/hyrax/app/assets/images/final-icons-01-100.png differ diff --git a/hyrax/app/assets/images/final-icons-02-100.png b/hyrax/app/assets/images/final-icons-02-100.png new file mode 100644 index 00000000..50089a61 Binary files /dev/null and b/hyrax/app/assets/images/final-icons-02-100.png differ diff --git a/hyrax/app/assets/images/final-icons-03-100.png b/hyrax/app/assets/images/final-icons-03-100.png new file mode 100644 index 00000000..245be950 Binary files /dev/null and b/hyrax/app/assets/images/final-icons-03-100.png differ diff --git a/hyrax/app/assets/images/final-icons-04-100.png b/hyrax/app/assets/images/final-icons-04-100.png new file mode 100644 index 00000000..a8dc0e01 Binary files /dev/null and b/hyrax/app/assets/images/final-icons-04-100.png differ diff --git a/hyrax/app/assets/images/final-icons-05-100.png b/hyrax/app/assets/images/final-icons-05-100.png new file mode 100644 index 00000000..e6bebfa0 Binary files /dev/null and b/hyrax/app/assets/images/final-icons-05-100.png differ diff --git a/hyrax/app/assets/javascripts/application.js b/hyrax/app/assets/javascripts/application.js index 876b8333..358c0e80 100644 --- a/hyrax/app/assets/javascripts/application.js +++ b/hyrax/app/assets/javascripts/application.js @@ -10,16 +10,17 @@ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // +//= require turbolinks +// //= require jquery //= require jquery_ujs //= require dataTables/jquery.dataTables //= require dataTables/bootstrap/3/jquery.dataTables.bootstrap -//= require jquery_ujs -//= require turbolinks +//= require bootstrap-datepicker +//= require csv_preview // // Required by Blacklight //= require blacklight/blacklight //= require_tree . //= require hyrax - diff --git a/hyrax/app/assets/javascripts/csv_preview.js b/hyrax/app/assets/javascripts/csv_preview.js new file mode 100644 index 00000000..f28492da --- /dev/null +++ b/hyrax/app/assets/javascripts/csv_preview.js @@ -0,0 +1,31 @@ +$( document ).on('turbolinks:load', function() { + $('.csv-preview').each(function() { + var preview = $(this); + $.ajax({ + url: preview.data('url'), + success: function (data) { + preview.find('.csv-preview-error').hide(); + preview.find('.csv-preview-datatable').DataTable({ + data: data.data, + columns: data.columns.map(function (name) { + if (name === null) { + return { title: '' }; + } else { + return {title: name.replace(/[\_\-]/g, ' ')}; + } + }), + order: [] + }); + preview.find('.csv-preview-title').text('Preview: ' + data.file_name); + if (data.total_rows > data.maximum_rows) { + preview.find('.csv-preview-size').text('preview is limited to the first ' + data.maximum_rows + ' records, the full file contains ' + data.total_rows + ' records').show(); + } else { + preview.find('.csv-preview-size').hide(); + } + }, + error: function() { + preview.find('.csv-preview-error').show(); + } + }); + }); +} ); diff --git a/hyrax/app/assets/javascripts/date_picker_options.js b/hyrax/app/assets/javascripts/date_picker_options.js new file mode 100644 index 00000000..6da1cd89 --- /dev/null +++ b/hyrax/app/assets/javascripts/date_picker_options.js @@ -0,0 +1,3 @@ +Blacklight.onLoad(function() { + $.fn.datepicker.defaults.format = "dd/mm/yyyy"; +}); diff --git a/hyrax/app/assets/javascripts/manage_repeating_nested_fields.js b/hyrax/app/assets/javascripts/manage_repeating_nested_fields.js new file mode 100644 index 00000000..9e5d1c5e --- /dev/null +++ b/hyrax/app/assets/javascripts/manage_repeating_nested_fields.js @@ -0,0 +1,38 @@ +Blacklight.onLoad(function() { + $('.multi-nested').manage_nested_fields(); +}); + +(function($){ + var DEFAULTS = { + /* callback to run after add is called */ + add: null, + /* callback to run after remove is called */ + remove: null, + + controlsHtml: '', + fieldWrapperClass: '.field-wrapper', + warningClass: '.has-warning', + listClass: '.listing', + removeInputClass: '.remove-hidden', + + addHtml: '', + addText: 'Add another', + + // removeHtml: '', + // removeText: 'Remove', + + labelControls: true + }; + + $.fn.manage_nested_fields = function(option) { + // var nested_editor = require('./nested_field_manager') + return this.each(function() { + var $this = $(this); + var data = $this.data('manage_nested_fields'); + var options = $.extend({}, DEFAULTS, $this.data(), typeof option == 'object' && option); + + if (!data) $this.data('manage_nested_fields', (data = new NestedFieldManager(this, options))); + }) + } + +})(jQuery); diff --git a/hyrax/app/assets/javascripts/nested_field_manager.js b/hyrax/app/assets/javascripts/nested_field_manager.js new file mode 100644 index 00000000..16708e52 --- /dev/null +++ b/hyrax/app/assets/javascripts/nested_field_manager.js @@ -0,0 +1,170 @@ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var NestedFieldManager = function () { + function NestedFieldManager(element, options) { + _classCallCheck(this, NestedFieldManager); + + this.element = $(element); + this.options = options; + this.warningClass = options.warningClass; + this.listClass = options.listClass; + this.fieldWrapperClass = options.fieldWrapperClass; + this.removeInputClass = options.removeInputClass; + + this.init(); + } + + _createClass(NestedFieldManager, [{ + key: 'init', + value: function init() { + // this._addInitialClasses(); + this._addAriaLiveRegions(); + this._attachEvents(); + this._addCallbacks(); + } + }, { + key: '_addAriaLiveRegions', + value: function _addAriaLiveRegions() { + $(this.element).find('.listing').attr('aria-live', 'polite'); + } + }, { + key: '_attachEvents', + value: function _attachEvents() { + var _this = this; + + this.element.on('click', '.remove', function (e) { + return _this.removeFromList(e); + }); + this.element.on('click', '.add', function (e) { + return _this.addToList(e); + }); + } + }, { + key: '_addCallbacks', + value: function _addCallbacks() { + this.element.bind('manage_nested_fields:add', this.options.add); + this.element.bind('manage_nested_fields:remove', this.options.remove); + } + }, { + key: 'addToList', + value: function addToList(event) { + event.preventDefault(); + var $listing = $(event.target).closest('.multi-nested').find(this.listClass); + var $listElements = $listing.children('li'); + var $activeField = $listElements.last(); + var $newId = $listElements.length; + var $currentId = $newId - 1; + if (this.inputIsEmpty($activeField)) { + this.displayEmptyWarning(); + $activeField.removeAttr('style'); + // $activeField.find('.remove-box').val('0'); + } else { + this.clearEmptyWarning(); + $listing.append(this._newField($activeField, $currentId, $newId)); + } + this._manageFocus(); + } + }, { + key: 'inputIsEmpty', + value: function inputIsEmpty($activeField) { + var $children = $activeField.find('.form-control').not(':hidden'); + var empty = 0; + $children.each(function () { + if ($.trim(this.value) === "") empty++; + }); + return empty === $children.length; + } + }, { + key: 'clearEmptyWarning', + value: function clearEmptyWarning() { + var $listing = $(this.listClass, this.element); + $listing.children(this.warningClass).remove(); + } + }, { + key: 'displayEmptyWarning', + value: function displayEmptyWarning() { + var $listing = $(this.listClass, this.element); + var $warningMessage = $("
cannot add another with empty field
"); + $listing.children(this.warningClass).remove(); + $listing.append($warningMessage); + } + }, { + key: '_newField', + value: function _newField($activeField, $currentId, $newId) { + var $newField = this.createNewField($activeField, $currentId, $newId); + return $newField; + } + }, { + key: '_manageFocus', + value: function _manageFocus() { + $(this.element).find(this.listClass).children('li:visible:last').find('.form-control').filter(':visible:first').focus(); + } + }, { + key: 'createNewField', + value: function createNewField($activeField, $currentId, $newId) { + var $newField = $activeField.clone(); + this.updateIndexInLabel($newField, $currentId, $newId); + var $newChildren = $newField.find('.form-control'); + $newChildren.val('').removeProp('required').removeAttr('style'); + this.updateIndexInId($newChildren, $currentId, $newId); + this.updateIndexInName($newChildren, $currentId, $newId); + $newChildren.first().focus(); + this.element.trigger("manage_nested_fields:add", $newChildren.first()); + return $newField; + } + }, { + key: 'updateIndexInLabel', + value: function updateIndexInLabel($newField, $currentId, $newId) { + // Modify name in label + var currentLabelPart = 'attributes_' + $currentId + '_'; + var newLabelPart = 'attributes_' + $newId + '_'; + $newField.find('label').each(function () { + var currentLabel = $(this).attr('for'); + var newLabel = currentLabel.replace(currentLabelPart, newLabelPart); + $(this).attr('for', newLabel); + }); + return $newField; + } + }, { + key: 'updateIndexInId', + value: function updateIndexInId($newChildren, $currentId, $newId) { + // modify id and name in newChildren + var $currentIdPart = new RegExp('attributes_' + $currentId + '_'); + var $newIdPart = 'attributes_' + $newId + '_'; + $newChildren.each(function () { + var $currentId = $(this).attr('id'); + var $newId = $currentId.replace($currentIdPart, $newIdPart); + $(this).attr('id', $newId); + }); + return $newChildren; + } + }, { + key: 'updateIndexInName', + value: function updateIndexInName($newChildren, $currentId, $newId) { + // modify id and name in newChildren + var $currentNamePart = new RegExp('[' + $currentId + ']'); + var $newnamePart = '[' + $newId + ']'; + $newChildren.each(function () { + var $currentName = $(this).attr('name'); + var $newName = $currentName.replace($currentNamePart, $newnamePart); + $(this).attr('name', $newName); + }); + return $newChildren; + } + }, { + key: 'removeFromList', + value: function removeFromList(event) { + event.preventDefault(); + var $activeField = $(event.target).parents(this.fieldWrapperClass); + $activeField.find(this.removeInputClass).val('1'); + $activeField.hide(); + this._manageFocus(); + } + }]); + + return NestedFieldManager; +}(); \ No newline at end of file diff --git a/hyrax/app/assets/stylesheets/application.css b/hyrax/app/assets/stylesheets/application.css index b7bf8eb3..f2bffcf5 100644 --- a/hyrax/app/assets/stylesheets/application.css +++ b/hyrax/app/assets/stylesheets/application.css @@ -10,6 +10,7 @@ * files in this directory. Styles in this file should be added after the last require_* statement. * It is generally better to create a new file per style scope. * + *= require bootstrap-datepicker3 *= require_tree . *= require dataTables/bootstrap/3/jquery.dataTables.bootstrap *= require_self diff --git a/hyrax/app/assets/stylesheets/browse_everything.scss b/hyrax/app/assets/stylesheets/browse_everything.scss new file mode 100644 index 00000000..48c4b3d1 --- /dev/null +++ b/hyrax/app/assets/stylesheets/browse_everything.scss @@ -0,0 +1,6 @@ +@import 'bootstrap-sprockets'; +@import 'bootstrap'; + +@import "font-awesome"; + +@import "browse_everything/browse_everything"; diff --git a/hyrax/app/assets/stylesheets/csv_preview.scss b/hyrax/app/assets/stylesheets/csv_preview.scss new file mode 100644 index 00000000..9fc68902 --- /dev/null +++ b/hyrax/app/assets/stylesheets/csv_preview.scss @@ -0,0 +1,3 @@ +.overflow-scroll { + overflow: scroll; +} diff --git a/hyrax/app/assets/stylesheets/ngdr.scss b/hyrax/app/assets/stylesheets/ngdr.scss new file mode 100644 index 00000000..4c7abdd4 --- /dev/null +++ b/hyrax/app/assets/stylesheets/ngdr.scss @@ -0,0 +1,124 @@ +//-------------- colours --------------- +$mdr-grey: #F4F4F4; +$mdr-green: #AFCA0B; +$mdr-green-light: #BEEB7D; + +//-------------- form css -------------- +form .listing, +form .inner-listing { + list-style: none; +} + +form .row { + padding-bottom: 5px; +} + +form .field-wrapper:not(:last-child) { + padding-bottom: 1em; + margin-bottom: 1em; + border-bottom: 2px solid $mdr-green; +} + +.multi-nested .form-group, +.multi-nested .listing { + margin-bottom: 0px; +} + +.multi-nested .btn { + padding-top: 0px; +} + +.multi-nested { + margin-bottom: 1em; + background-color: $mdr-grey; + padding: 10px; +} + +form .field-wrapper label[required="required"]::after { + content: " *"; + color: red; +} + +.nested-table, +.nested-table > tbody, +.nested-table > tbody > tr, +.nested-table > tbody > tr > th, +.nested-table > tbody > tr > td { + border-top: 0; + border-bottom: 0; + border-left: 0; + border-right: 0; + padding: 0px; +} + +.nested-table > tbody > tr.end > th, +.nested-table > tbody > tr.end > td { + padding-bottom: 10px; +} + +.inner-listing { + padding-left: 0px; +} + +.inner-nested { + margin-bottom: 1em; + padding: 10px; + background-color: $mdr-green-light; +} +//------------ display css ------------- +.each_metadata:not(:last-child) { + margin-bottom: 1em; + padding-bottom: 1em; + border-bottom: 1px solid #ddd; +} +.label-row { + color: #999; +} + +.panel-heading .accordion-toggle:after { + /* symbol for "opening" panels */ + font-family: 'Glyphicons Halflings'; /* essential for enabling glyphicon */ + content: "\e114"; /* adjust as needed, taken from bootstrap.css */ + float: right; /* adjust as needed */ + color: grey; /* adjust as needed */ +} +.panel-heading.collapsed .accordion-toggle:after { + /* symbol for "collapsed" panels */ + content: "\e080"; /* adjust as needed, taken from bootstrap.css */ +} +//-------------------------------------- + +//------------ UNIVERSAL VIEWER (ported from Hyrax master) @todo remove on upgrade to Hyrax 3.x ------------- + +/* pad the top and bottom universal viewer*/ +.viewer-wrapper { + position: relative; + overflow: hidden; + margin: 10px 0; +} + +.viewer-wrapper iframe { + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; +} + +// Show various footer, header, left and right panels on larger screens only +@media only screen and (min-width: 640px) { + .viewer-wrapper { + height: 640px; + } +} + +//-------------------------------------- + +div#announcement { + font-size: 1em; + background-color: #1E2022; +} + +.csv-preview-size { + text-align: right; +} diff --git a/hyrax/app/assets/stylesheets/theme.scss b/hyrax/app/assets/stylesheets/theme.scss new file mode 100644 index 00000000..14c7c1f0 --- /dev/null +++ b/hyrax/app/assets/stylesheets/theme.scss @@ -0,0 +1,261 @@ +//----------- fonts to be used --------- +@font-face { + font-family: "Galano Grotesque"; + src: font-url('GalanoGrotesqueBold.otf'); + font-weight: bold; + font-style: normal; +} +@font-face { + font-family: "Galano Grotesque"; + src: font-url('GalanoGrotesqueLight.otf'); + font-weight: normal; + font-style: normal; +} + +//---------- colours to be used -------- +$mdr-grey: #F4F4F4; +$mdr-black: #1E2022; +$mdr-green: #AFCA0B; +$mdr-green-light: #7DB928; +$mdr-green-dark: #51791A; + +//-------------- Fonts ----------------- +body { + font-family: "Galano Grotesque"; + font-size: 14px; + line-height: 1.428571429; + color: $mdr-black; +} + +//-------------- Headings -------------- +h1, .h1 { + font-family: "Galano Grotesque"; + font-size: 32px; +} + +h2, .modal-title, .h2 { + font-family: "Galano Grotesque"; + font-weight: bold; + font-size: 18px; + color: $mdr-black; +} + +h3, .h3 { + font-family: "Galano Grotesque"; + font-weight: bold; + font-size: 14px; + color: $mdr-black; +} + +//------------- anchor ----------------- +a, a:focus, a:hover, a:active { + color: $mdr-green-dark; +} + +// --------------- buttons ------------- +.btn { + border-radius: 0px; +} + +.btn-primary, .btn-primary:focus, .btn-primary:hover, .btn-primary:active, + { + background-color: $mdr-black; + border-color: $mdr-black; + color: $mdr-green; + text-transform: uppercase; + font-weight: bold; + border-radius: 0px; +} + +.btn-default, .btn-default:focus, .btn-default:hover, .btn-default:active, +.btn-success, .btn-success:focus, .btn-success:hover, .btn-success:active { + background-color: $mdr-black; + border-color: $mdr-black; + color: $mdr-green; + text-transform: uppercase; + border-radius: 0px; +} + +a.btn-primary, +a.btn-primary:focus, +a.btn-primary:hover, +a.btn-primary:active { + color: $mdr-green; +} + +.glyphicon-search { + color: $mdr-green; +} + +.facets-toggle, td.toggle input[type="submit"] { + border-radius: 0px; +} + +// ------------- label ----------------- +.label { + background-color: inherit; + border: none; +} + +.label-primary { + color: $mdr-green; +} + +.label-success { + color: $mdr-green; +} + +.label-info { + color: #2c76c7; +} + +.label-warning { + color: #e65c00; +} + +.label-danger { + color: #FF0000; +} + +// ------------- dropdown -------------- +#sort-dropdown .dropdown-toggle, #per_page-dropdown .dropdown-toggle { + color: $mdr-green; +} + +//-------------- Header ---------------- + +// .recent-field-fluid > .navbar-header, .recent-field-fluid > .navbar-collapse { +// margin-top: 15px; +// } + +#masthead { + background-color: $mdr-black; +} + +.navbar-inverse .navbar-nav > li.dropdown > a { + color: $mdr-green; + font-weight: bold; +} + +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + color: $mdr-green; +} + +.navbar { + min-height: 80px; +} + +.navbar + .navbar { + margin-top: 0px; +} + +.navbar-brand { + height: 80px; +} + +.navbar-right { + margin-top: 15px; +} + +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #fff; + background-color: #3c3c3c; + font-weight: bold; +} + +nav.searchbar { + margin-bottom: 0px; + background-color: $mdr-green-light; +} + +.searchbar > .recent-field-fluid { + margin-bottom: 0px; +} + +.searchbar-left { + padding-top: 15px; +} + +.navbar-left { + // margin-top: 15px; + float: left !important; +} + +#search-submit-header { + color: white; +} + +// ------------- footer ---------------- +.site-footer { + height: 60px; + padding: 20px; + background-color: $mdr-black; + color: #fff; + font-weight: bold; +} + +// ------------- homepage ----------------- +.homepage-icon { + margin-top: 15px; + margin-bottom: 15px; +} + +.homepage-row { + padding-bottom: 30px; +} + +.homepage-row:first-child { + padding-top: 30px; +} + +.homepage-row:nth-child(odd) { + background: $mdr-grey; +} + +.homepage-row:nth-child(even) { + background: #FFF; +} + +.home-recently-uploaded, +.home-featured-works, +.home-featured-researcher { + max-width: 80%; + margin-left: auto; + margin-right: auto; +} + +.home-browse { + text-transform: uppercase; +} + +//--------------- dashboard ----------- +body.dashboard { + padding-top: 80px; +} + +//--------------- work show ------------ +.work-type-tag { + color: $mdr-green; +} + +//-------------- Search ---------------- +.facet-field-heading { + font-weight: normal; + font-size: 14px; +} + +.facet_select { + color: $mdr-black; +} + +.facet-values li .selected { + color: #FF0000; +} + +.facet-values .remove { + color: #FF0000; +} diff --git a/hyrax/app/controllers/application_controller.rb b/hyrax/app/controllers/application_controller.rb index c324c443..2669f3f0 100644 --- a/hyrax/app/controllers/application_controller.rb +++ b/hyrax/app/controllers/application_controller.rb @@ -1,4 +1,8 @@ class ApplicationController < ActionController::Base + rescue_from DeviseLdapAuthenticatable::LdapException do |exception| + render :text => exception, :status => 500 + end + helper Openseadragon::OpenseadragonHelper # Adds a few additional behaviors into the application controller include Blacklight::Controller @@ -10,6 +14,21 @@ class ApplicationController < ActionController::Base include Hyrax::ThemedLayoutController with_themed_layout '1_column' - protect_from_forgery with: :exception + + protected + + # Override Devise method to redirect to dashboard after signing in + def after_sign_in_path_for(resource) + new_path = '/dashboard/my/works' + sign_in_url = new_user_session_url + stored_path = stored_location_for(resource) + # if request.referer != root_path && request.referer != sign_in_url + # stored_path || request.referer || new_path + # else + # stored_path || new_path + # end + # Trying fix for redirect loop + stored_path || new_path + end end diff --git a/hyrax/app/controllers/catalog_controller.rb b/hyrax/app/controllers/catalog_controller.rb index b8fe6045..91e52625 100644 --- a/hyrax/app/controllers/catalog_controller.rb +++ b/hyrax/app/controllers/catalog_controller.rb @@ -1,6 +1,8 @@ class CatalogController < ApplicationController include Hydra::Catalog include Hydra::Controller::ControllerBehavior + include BlacklightOaiProvider::CatalogControllerBehavior + include DisableApiBehavior # This filter applies the hydra access controls before_action :enforce_show_permissions, only: :show @@ -14,11 +16,12 @@ def self.modified_field end configure_blacklight do |config| + config.http_method = :post + config.view.gallery.partials = [:index_header, :index] config.view.masonry.partials = [:index] config.view.slideshow.partials = [:index] - config.show.tile_source_field = :content_metadata_image_iiif_info_ssm config.show.partials.insert(1, :openseadragon) config.search_builder_class = Hyrax::CatalogSearchBuilder @@ -27,6 +30,8 @@ def self.modified_field config.view.gallery.partials = [:index_header, :index] config.view.slideshow.partials = [:index] + config.oai = OAI_CONFIG + ## Default parameters to send to solr for all search-like requests. See also SolrHelper#solr_search_params config.default_solr_params = { qt: "search", @@ -39,23 +44,19 @@ def self.modified_field config.index.display_type_field = solr_name("has_model", :symbol) config.index.thumbnail_field = 'thumbnail_path_ss' + # solr fields that will be treated as facets by the blacklight application # The ordering of the field names is the order of the display - config.add_facet_field solr_name("human_readable_type", :facetable), label: "Type", limit: 5 - config.add_facet_field solr_name("resource_type", :facetable), label: "Resource Type", limit: 5 - config.add_facet_field solr_name("creator", :facetable), limit: 5 - config.add_facet_field solr_name("contributor", :facetable), label: "Contributor", limit: 5 - config.add_facet_field solr_name("keyword", :facetable), limit: 5 - config.add_facet_field solr_name("subject", :facetable), limit: 5 - config.add_facet_field solr_name("language", :facetable), limit: 5 - config.add_facet_field solr_name("based_near_label", :facetable), limit: 5 - config.add_facet_field solr_name("publisher", :facetable), limit: 5 - config.add_facet_field solr_name("file_format", :facetable), limit: 5 - config.add_facet_field solr_name('member_of_collections', :symbol), limit: 5, label: 'Collections' + facet_fields = (DatasetIndexer.facet_fields + + PublicationIndexer.facet_fields + + ImageIndexer.facet_fields).uniq + facet_fields.each do |fld| + config.add_facet_field fld, limit: 5 + end # The generic_type isn't displayed on the facet list # It's used to give a label to the filter that comes from the user profile - config.add_facet_field solr_name("generic_type", :facetable), if: false + config.add_facet_field solr_name('generic_type', :facetable), if: false # Have BL send all facet field names to Solr, which has been the default # previously. Simply remove these lines if you'd rather use Solr request @@ -64,47 +65,50 @@ def self.modified_field # solr fields to be displayed in the index (search results) view # The ordering of the field names is the order of the display - config.add_index_field solr_name("title", :stored_searchable), label: "Title", itemprop: 'name', if: false - config.add_index_field solr_name("description", :stored_searchable), itemprop: 'description', helper_method: :iconify_auto_link - config.add_index_field solr_name("keyword", :stored_searchable), itemprop: 'keywords', link_to_search: solr_name("keyword", :facetable) - config.add_index_field solr_name("subject", :stored_searchable), itemprop: 'about', link_to_search: solr_name("subject", :facetable) - config.add_index_field solr_name("creator", :stored_searchable), itemprop: 'creator', link_to_search: solr_name("creator", :facetable) - config.add_index_field solr_name("contributor", :stored_searchable), itemprop: 'contributor', link_to_search: solr_name("contributor", :facetable) - config.add_index_field solr_name("proxy_depositor", :symbol), label: "Depositor", helper_method: :link_to_profile - config.add_index_field solr_name("depositor"), label: "Owner", helper_method: :link_to_profile - config.add_index_field solr_name("publisher", :stored_searchable), itemprop: 'publisher', link_to_search: solr_name("publisher", :facetable) - config.add_index_field solr_name("based_near_label", :stored_searchable), itemprop: 'contentLocation', link_to_search: solr_name("based_near_label", :facetable) - config.add_index_field solr_name("language", :stored_searchable), itemprop: 'inLanguage', link_to_search: solr_name("language", :facetable) - config.add_index_field solr_name("date_uploaded", :stored_sortable, type: :date), itemprop: 'datePublished', helper_method: :human_readable_date - config.add_index_field solr_name("date_modified", :stored_sortable, type: :date), itemprop: 'dateModified', helper_method: :human_readable_date - config.add_index_field solr_name("date_created", :stored_searchable), itemprop: 'dateCreated' - config.add_index_field solr_name("rights_statement", :stored_searchable), helper_method: :rights_statement_links - config.add_index_field solr_name("license", :stored_searchable), helper_method: :license_links - config.add_index_field solr_name("resource_type", :stored_searchable), label: "Resource Type", link_to_search: solr_name("resource_type", :facetable) - config.add_index_field solr_name("file_format", :stored_searchable), link_to_search: solr_name("file_format", :facetable) - config.add_index_field solr_name("identifier", :stored_searchable), helper_method: :index_field_link, field_name: 'identifier' - config.add_index_field solr_name("embargo_release_date", :stored_sortable, type: :date), label: "Embargo release date", helper_method: :human_readable_date - config.add_index_field solr_name("lease_expiration_date", :stored_sortable, type: :date), label: "Lease expiration date", helper_method: :human_readable_date + config.add_index_field solr_name('title', :stored_searchable), label: 'Title', itemprop: 'name', if: false + config.add_index_field solr_name('description', :stored_searchable), itemprop: 'description', helper_method: :iconify_auto_link, if: lambda { |context, field_config, document| context.can?(:read_abstract, document.hydra_model) } + config.add_index_field solr_name('keyword', :stored_searchable), itemprop: 'keywords', link_to_search: solr_name('keyword', :facetable), if: lambda { |context, field_config, document| context.can?(:read_keyword, document.hydra_model) } + config.add_index_field solr_name('subject', :stored_searchable), itemprop: 'about', link_to_search: solr_name('subject', :facetable), if: lambda { |context, field_config, document| context.can?(:read_subject, document.hydra_model) } + # config.add_index_field solr_name('creator', :stored_searchable), itemprop: 'creator', link_to_search: solr_name('creator', :facetable) + # config.add_index_field solr_name('contributor', :stored_searchable), itemprop: 'contributor', link_to_search: solr_name('contributor', :facetable) + config.add_index_field solr_name('complex_person_author', :stored_searchable), itemprop: 'author', link_to_search: solr_name('complex_person_author', :facetable) + # config.add_index_field solr_name('complex_person_editor', :stored_searchable), itemprop: 'editor', link_to_search: solr_name('complex_person_editor', :facetable) + # config.add_index_field solr_name('complex_person_translator', :stored_searchable), itemprop: 'translator', link_to_search: solr_name('complex_person_translator', :facetable) + config.add_index_field solr_name('complex_person_data_depositor', :stored_searchable), itemprop: 'data depositor', link_to_search: solr_name('complex_person_data_depositor', :facetable) + config.add_index_field solr_name('complex_person_data_curator', :stored_searchable), itemprop: 'data curator', link_to_search: solr_name('complex_person_data_curator', :facetable) + config.add_index_field solr_name('complex_person_operator', :stored_searchable), itemprop: 'operator', link_to_search: solr_name('complex_person_operator', :facetable) + config.add_index_field solr_name('complex_person_other', :stored_searchable), itemprop: 'creator or contributor', link_to_search: solr_name('complex_person_other', :facetable) + # config.add_index_field solr_name('proxy_depositor', :symbol), label: 'Depositor', helper_method: :link_to_profile + # config.add_index_field solr_name('depositor'), label: 'Owner', helper_method: :link_to_profile + config.add_index_field solr_name('data_origin', :stored_searchable), itemprop: 'data_origin', link_to_search: solr_name('data_origin', :facetable) + config.add_index_field solr_name('complex_specimen_type', :stored_searchable), itemprop: 'specimen' + config.add_index_field solr_name('complex_source_title', :stored_searchable), itemprop: 'journal' + config.add_index_field solr_name('complex_date_published', :stored_searchable, type: :date), itemprop: 'datePublished', helper_method: :human_readable_date + config.add_index_field solr_name('publisher', :stored_searchable), itemprop: 'publisher', link_to_search: solr_name('publisher', :facetable) + # config.add_index_field solr_name('based_near_label', :stored_searchable), itemprop: 'contentLocation', link_to_search: solr_name('based_near_label', :facetable) + # config.add_index_field solr_name('language', :stored_searchable), itemprop: 'inLanguage', link_to_search: solr_name('language', :facetable) + config.add_index_field solr_name('date_uploaded', :stored_sortable, type: :date), itemprop: 'datePublished', helper_method: :human_readable_date + config.add_index_field solr_name('date_modified', :stored_sortable, type: :date), itemprop: 'dateModified', helper_method: :human_readable_date + config.add_index_field solr_name('date_created', :stored_searchable), itemprop: 'dateCreated' + config.add_index_field solr_name('rights_statement', :stored_searchable), helper_method: :rights_statement_links, if: lambda { |context, field_config, document| context.can?(:read_rights, document.hydra_model) } + config.add_index_field solr_name('license', :stored_searchable), helper_method: :license_links + config.add_index_field solr_name('resource_type', :stored_searchable), label: 'Resource Type', link_to_search: solr_name('resource_type', :facetable), if: lambda { |context, field_config, document| context.can?(:read_resource_type, document.hydra_model) } + config.add_index_field solr_name('file_format', :stored_searchable), link_to_search: solr_name('file_format', :facetable) + config.add_index_field solr_name('identifier', :stored_searchable), helper_method: :index_field_link, field_name: 'identifier' + config.add_index_field solr_name('embargo_release_date', :stored_sortable, type: :date), label: 'Embargo release date', helper_method: :human_readable_date + config.add_index_field solr_name('lease_expiration_date', :stored_sortable, type: :date), label: 'Lease expiration date', helper_method: :human_readable_date + config.add_index_field solr_name('place', :stored_searchable), itemprop: 'place', link_to_search: solr_name('place', :facetable) + config.add_index_field solr_name('status', :stored_searchable), itemprop: 'status', link_to_search: solr_name('status', :facetable) + config.add_index_field solr_name('issue', :stored_searchable), label: 'Issue' # solr fields to be displayed in the show (single result) view # The ordering of the field names is the order of the display - config.add_show_field solr_name("title", :stored_searchable) - config.add_show_field solr_name("description", :stored_searchable) - config.add_show_field solr_name("keyword", :stored_searchable) - config.add_show_field solr_name("subject", :stored_searchable) - config.add_show_field solr_name("creator", :stored_searchable) - config.add_show_field solr_name("contributor", :stored_searchable) - config.add_show_field solr_name("publisher", :stored_searchable) - config.add_show_field solr_name("based_near_label", :stored_searchable) - config.add_show_field solr_name("language", :stored_searchable) - config.add_show_field solr_name("date_uploaded", :stored_searchable) - config.add_show_field solr_name("date_modified", :stored_searchable) - config.add_show_field solr_name("date_created", :stored_searchable) - config.add_show_field solr_name("rights_statement", :stored_searchable) - config.add_show_field solr_name("license", :stored_searchable) - config.add_show_field solr_name("resource_type", :stored_searchable), label: "Resource Type" - config.add_show_field solr_name("format", :stored_searchable) - config.add_show_field solr_name("identifier", :stored_searchable) + show_fields = (DatasetIndexer.show_fields + + PublicationIndexer.show_fields + + ImageIndexer.show_fields).uniq + show_fields.each do |fld| + config.add_show_field fld + end # "fielded" search configuration. Used by pulldown among other places. # For supported keys in hash, see rdoc for Blacklight::SearchFields @@ -124,7 +128,9 @@ def self.modified_field # solr request handler? The one set in config[:default_solr_parameters][:qt], # since we aren't specifying it otherwise. config.add_search_field('all_fields', label: 'All Fields') do |field| - all_names = config.show_fields.values.map(&:field).join(" ") + all_names = (DatasetIndexer.search_fields + + PublicationIndexer.search_fields + + ImageIndexer.search_fields).uniq.join(" ") title_name = solr_name("title", :stored_searchable) field.solr_parameters = { qf: "#{all_names} file_format_tesim all_text_timv", @@ -135,24 +141,13 @@ def self.modified_field # Now we see how to over-ride Solr request handler defaults, in this # case for a BL "search field", which is really a dismax aggregate # of Solr search fields. - # creator, title, description, publisher, date_created, - # subject, language, resource_type, format, identifier, based_near, - config.add_search_field('contributor') do |field| + config.add_search_field('complex_person') do |field| # solr_parameters hash are sent to Solr as ordinary url query params. - # :solr_local_parameters will be sent using Solr LocalParams # syntax, as eg {! qf=$title_qf }. This is neccesary to use # Solr parameter de-referencing like $title_qf. # See: http://wiki.apache.org/solr/LocalParams - solr_name = solr_name("contributor", :stored_searchable) - field.solr_local_parameters = { - qf: solr_name, - pf: solr_name - } - end - - config.add_search_field('creator') do |field| - solr_name = solr_name("creator", :stored_searchable) + solr_name = solr_name("complex_person", :stored_searchable) field.solr_local_parameters = { qf: solr_name, pf: solr_name @@ -232,15 +227,6 @@ def self.modified_field } end - config.add_search_field('based_near') do |field| - field.label = "Location" - solr_name = solr_name("based_near_label", :stored_searchable) - field.solr_local_parameters = { - qf: solr_name, - pf: solr_name - } - end - config.add_search_field('keyword') do |field| solr_name = solr_name("keyword", :stored_searchable) field.solr_local_parameters = { diff --git a/hyrax/app/controllers/concerns/complex_fields_behavior.rb b/hyrax/app/controllers/concerns/complex_fields_behavior.rb new file mode 100644 index 00000000..610e60e6 --- /dev/null +++ b/hyrax/app/controllers/concerns/complex_fields_behavior.rb @@ -0,0 +1,153 @@ +module ComplexFieldsBehavior + private + + def is_complex?(attribute_name) + complex_prefixes = %w[ + complex + instrument_function + manufacturer + managing_organization + supplier + manufacturer + custom_property + ] + complex_prefixes.each { |prefix| return true if attribute_name.to_s.start_with? prefix } + false + end + + def hash_is_blank?(hash_param) + other_keys = hash_param.keys - %w[id _destroy] + return false unless other_keys.blank? + if hash_param.fetch('id', nil) && hash_param.fetch('_destroy', nil) + return false if ['true', '1', true, 1].include? hash_param['_destroy'] + end + true + end + + # Delete person/organization from instrument and specimen_type where the record contains + # only role=operator (person) or purpose=manufacturer/supplier (organization) + # this happens because we are validating nothing on instrument or speciment_type + # This is temporary until proper validation is in place + def cleanup_instrument_and_specimen_type(attribute) + # complex_instrument + attribute['complex_instrument_attributes'].each_with_index do |complex_instrument, index| + if complex_instrument['complex_person_attributes'].present? + complex_instrument['complex_person_attributes'].each_with_index do |complex_person, i| + if complex_person['name'].blank? && complex_person['role'].include?('operator') + attribute['complex_instrument_attributes'][index]['complex_person_attributes'].delete_at(i) + end + end + end + if complex_instrument['manufacturer_attributes'].present? + complex_instrument['manufacturer_attributes'].each_with_index do |manufacturer, i| + if manufacturer['organization'].blank? && manufacturer['purpose'].include?('Manufacturer') + attribute['complex_instrument_attributes'][index]['manufacturer_attributes'].delete_at(i) + end + end + end + if complex_instrument['managing_organization_attributes'].present? + complex_instrument['managing_organization_attributes'].each_with_index do |managing_organization, i| + if managing_organization['organization'].blank? && managing_organization['purpose'].include?('Managing organization') + attribute['complex_instrument_attributes'][index]['managing_organization_attributes'].delete_at(i) + end + end + end + if complex_instrument['complex_date_attributes'].present? + complex_instrument['complex_date_attributes'].each_with_index do |complex_date, i| + if complex_date.present? + if complex_date['date'].blank? && complex_date['description'].include?('Processed') + attribute['complex_instrument_attributes'][index]['complex_date_attributes'].delete_at(i) + end + end + end + end + end + # complex_specimen_type + attribute['complex_specimen_type_attributes'].each_with_index do |complex_specimen_type, index| + if complex_specimen_type['complex_purchase_record_attributes'].present? + complex_specimen_type['complex_purchase_record_attributes'].each_with_index do |complex_purchase_record, i| + if complex_purchase_record['supplier_attributes'].present? + complex_purchase_record['supplier_attributes'].each_with_index do |supplier, ii| + if supplier['organization'].blank? && supplier['purpose'].include?('Supplier') + attribute['complex_specimen_type_attributes'][index]['complex_purchase_record_attributes'][i]['supplier_attributes'].delete_at(ii) + end + end + end + complex_purchase_record['manufacturer_attributes'].each_with_index do |manufacturer, ii| + if manufacturer['organization'].blank? && manufacturer['purpose'].include?('Manufacturer') + attribute['complex_specimen_type_attributes'][index]['complex_purchase_record_attributes'][i]['manufacturer_attributes'].delete_at(ii) + end + end + end + end + end + attribute + end + + def cleanup_params(attribute) + if attribute.is_a?(Hash) && attribute.keys.all? { |k| k !~ /\D/ } + # removes hashes with integer keys + cleanup_params(attribute.values) + elsif attribute.is_a? Hash + new_attribute = {} + attribute.each do |k, v| + v = cleanup_params(v) if is_complex?(k) + v = cleanup_params(v) if v.is_a? Array + next if v.blank? + new_attribute[k] = if skip_controlled.include?(k) || k.end_with?('_attributes') + v + else + sanitize_value(v) + end + end + new_attribute.compact unless hash_is_blank?(new_attribute) + elsif attribute.is_a? Array + new_attr = [] + attribute.reject(&:blank?).each do |v| + v = cleanup_params(v) if v.is_a? Hash + new_attr << sanitize_value(v) unless v.blank? + end + new_attr.reject(&:blank?) + elsif attribute.blank? + nil + else + attribute + end + end + + def sanitize_value(value) + if value.is_a? Array + value.map do |v| + if v.is_a? String + Loofah.fragment(v).scrub!(:escape).to_s + else + v + end + end + elsif value.is_a? String + Loofah.fragment(value).scrub!(:escape).to_s + else + value + end + end + + # Don't scrub controlled fields + def skip_controlled + %w[ + representative_id + thumbnail_id + visibility_during_embargo + visibility_after_embargo + visibility_during_lease + visibility_after_lease + visibility + admin_set_id + data_origin + version + _destroy + id + purpose + role + ] + end +end diff --git a/hyrax/app/controllers/concerns/disable_api_behavior.rb b/hyrax/app/controllers/concerns/disable_api_behavior.rb new file mode 100644 index 00000000..6bf87048 --- /dev/null +++ b/hyrax/app/controllers/concerns/disable_api_behavior.rb @@ -0,0 +1,19 @@ +# Temporarily disable API behaviour, see https://github.com/antleaf/nims-mdr-development/issues/241 + +module DisableApiBehavior + def show + respond_to do |format| + format.html { super } + format.json { render json: { error: 'API is currently unavailable' }, status: 400 } + format.any { render plain: 'API is currently unavailable', content_type: 'text/plain', status: 400} + end + end + + def index + respond_to do |format| + format.html { super } + format.json { render json: { error: 'API is currently unavailable' }, status: 400 } + format.any { render plain: 'API is currently unavailable', content_type: 'text/plain', status: 400} + end + end +end diff --git a/hyrax/app/controllers/exports_controller.rb b/hyrax/app/controllers/exports_controller.rb new file mode 100644 index 00000000..6ad04a92 --- /dev/null +++ b/hyrax/app/controllers/exports_controller.rb @@ -0,0 +1,32 @@ +require 'csv' +require 'json' + +class ExportsController < Hyrax::DownloadsController + MAXIMUM_ROWS = 100 + + def export + if file.present? && file.mime_type.present? && file.mime_type =~ /^(?:text|application)\/csv$/i + render json: csv_as_datatable + else + render :json => { error: 'Unknown or unsupported file type' }, :status => :bad_request + end + end + + private + + def csv_as_datatable + # CSV files come in many different flavours (character encodings), e.g. ASCII-8BIT, UTF-8, ISO-8859-1 or Windows-1252. + # It is not possible to detect the character encoding of a file with 100% accuracy. So we will assume files are in UTF-8 + # (as the world is moving that way) and scrub out any characters which do not conform to UTF-8. This "lossy" approach + # should be ok as this export is merely used to provide a preview of the file, rather than the actual file itself. + content = file.content.force_encoding(Encoding::UTF_8).scrub + csv = CSV.parse(content, headers: true) + { + columns: csv.headers, + data: csv.take(MAXIMUM_ROWS).map(&:values_at), + total_rows: csv.size, + maximum_rows: MAXIMUM_ROWS, + file_name: file_name + } + end +end diff --git a/hyrax/app/controllers/hyrax/citations_controller.rb b/hyrax/app/controllers/hyrax/citations_controller.rb new file mode 100644 index 00000000..9da5d452 --- /dev/null +++ b/hyrax/app/controllers/hyrax/citations_controller.rb @@ -0,0 +1,44 @@ +module Hyrax + class CitationsController < ApplicationController + include WorksControllerBehavior + include Breadcrumbs + include SingularSubresourceController + prepend ::DisableApiBehavior + + # Overrides decide_layout from WorksControllerBehavior + with_themed_layout '1_column' + + before_action :build_breadcrumbs, only: [:work, :file] + + def work + show + end + + def file + # We set _@presenter_ here so it isn't set in WorksControllerBehavior#presenter + # which is intended to find works (not files) + solr_file = ::SolrDocument.find(params[:id]) + authorize! :show, solr_file + @presenter = NimsFileSetPresenter.new(solr_file, current_ability, request) + show + end + + private + + # nims override to select correct presenter + def show_presenter + case find_work.class.to_s + when 'Dataset' + DatasetPresenter + when 'Image' + ImagePresenter + when 'Publication' + PublicationPresenter + when 'Work' + WorkPresenter + else + WorkShowPresenter + end + end + end +end diff --git a/hyrax/app/controllers/hyrax/datasets_controller.rb b/hyrax/app/controllers/hyrax/datasets_controller.rb new file mode 100644 index 00000000..110fff60 --- /dev/null +++ b/hyrax/app/controllers/hyrax/datasets_controller.rb @@ -0,0 +1,32 @@ +# Generated via +# `rails generate hyrax:work Dataset` +module Hyrax + # Generated controller for Dataset + class DatasetsController < ApplicationController + # Adds Hyrax behaviors to the controller. + include Hyrax::WorksControllerBehavior + include Hyrax::BreadcrumbsForWorks + include ::ComplexFieldsBehavior + prepend ::DisableApiBehavior + + self.curation_concern_type = ::Dataset + + # Use this line if you want to use a custom presenter + self.show_presenter = Hyrax::DatasetPresenter + + def create + safe_dataset_params = params['dataset'].permit(::Hyrax::DatasetForm.build_permitted_params) + # NB: need to cleanup twice + params['dataset'] = cleanup_params(cleanup_instrument_and_specimen_type(cleanup_params(safe_dataset_params.to_h))) + super + end + + def update + safe_dataset_params = params['dataset'].permit(::Hyrax::DatasetForm.build_permitted_params) + # NB: need to cleanup twice + params['dataset'] = cleanup_params(cleanup_instrument_and_specimen_type(cleanup_params(safe_dataset_params.to_h))) + super + end + + end +end diff --git a/hyrax/app/controllers/hyrax/file_sets_controller.rb b/hyrax/app/controllers/hyrax/file_sets_controller.rb new file mode 100644 index 00000000..9ac264aa --- /dev/null +++ b/hyrax/app/controllers/hyrax/file_sets_controller.rb @@ -0,0 +1,192 @@ +module Hyrax + class FileSetsController < ApplicationController + include Blacklight::Base + include Blacklight::AccessControls::Catalog + include Hyrax::Breadcrumbs + prepend ::DisableApiBehavior + + before_action :authenticate_user!, except: [:show, :citation, :stats] + load_and_authorize_resource class: ::FileSet, except: :show + before_action :build_breadcrumbs, only: [:show, :edit, :stats] + + # provides the help_text view method + helper PermissionsHelper + + helper_method :curation_concern + copy_blacklight_config_from(::CatalogController) + + class_attribute :show_presenter, :form_class + self.show_presenter = NimsFileSetPresenter + self.form_class = Hyrax::Forms::FileSetEditForm + + # A little bit of explanation, CanCan(Can) sets the @file_set via the .load_and_authorize_resource + # method. However the interface for various CurationConcern modules leverages the #curation_concern method + # Thus we have file_set and curation_concern that are aliases for each other. + attr_accessor :file_set + alias curation_concern file_set + private :file_set= + alias curation_concern= file_set= + private :curation_concern= + helper_method :file_set + + layout :decide_layout + + # GET /concern/file_sets/:id + def edit + initialize_edit_form + end + + # GET /concern/parent/:parent_id/file_sets/:id + def show + respond_to do |wants| + wants.html { presenter } + wants.json { presenter } + additional_response_formats(wants) + end + end + + # DELETE /concern/file_sets/:id + def destroy + parent = curation_concern.parent + actor.destroy + redirect_to [main_app, parent], notice: 'The file has been deleted.' + end + + # PATCH /concern/file_sets/:id + def update + if attempt_update + after_update_response + else + after_update_failure_response + end + rescue RSolr::Error::Http => error + flash[:error] = error.message + logger.error "FileSetsController::update rescued #{error.class}\n\t#{error.message}\n #{error.backtrace.join("\n")}\n\n" + render action: 'edit' + end + + # GET /files/:id/stats + def stats + @stats = FileUsage.new(params[:id]) + end + + # GET /files/:id/citation + def citation; end + + private + + # this is provided so that implementing application can override this behavior and map params to different attributes + def update_metadata + file_attributes = form_class.model_attributes(attributes) + actor.update_metadata(file_attributes) + end + + # Override Hyrax 2.6.0 - pass Hyrax::UploadedFile to actor.update_content + def attempt_update + if wants_to_revert? + actor.revert_content(params[:revision]) + elsif params.key?(:file_set) + if params[:file_set].key?(:files) + actor.update_content(uploaded_file_from_path) + else + update_metadata + end + end + end + + # Override Hyrax 2.6.0 - create an Hyrax::UploadedFile from the file upload + def uploaded_file_from_path + uploaded_file = CarrierWave::SanitizedFile.new(params[:file_set][:files].first) + Hyrax::UploadedFile.create(user_id: current_user.id, file: uploaded_file) + end + + def after_update_response + respond_to do |wants| + wants.html do + redirect_to [main_app, curation_concern], notice: "The file #{view_context.link_to(curation_concern, [main_app, curation_concern])} has been updated." + end + wants.json do + @presenter = show_presenter.new(curation_concern, current_ability) + render :show, status: :ok, location: polymorphic_path([main_app, curation_concern]) + end + end + end + + def after_update_failure_response + respond_to do |wants| + wants.html do + initialize_edit_form + flash[:error] = "There was a problem processing your request." + render 'edit', status: :unprocessable_entity + end + wants.json { render_json_response(response_type: :unprocessable_entity, options: { errors: curation_concern.errors }) } + end + end + + def add_breadcrumb_for_controller + add_breadcrumb I18n.t('hyrax.dashboard.my.works'), hyrax.my_works_path + end + + def add_breadcrumb_for_action + case action_name + when 'edit'.freeze + add_breadcrumb I18n.t("hyrax.file_set.browse_view"), main_app.hyrax_file_set_path(params["id"]) + when 'show'.freeze + add_breadcrumb presenter.parent.to_s, main_app.polymorphic_path(presenter.parent) + add_breadcrumb presenter.to_s, main_app.polymorphic_path(presenter) + end + end + + # Override of Blacklight::RequestBuilders + def search_builder_class + Hyrax::FileSetSearchBuilder + end + + def initialize_edit_form + @parent = @file_set.in_objects.first + original = @file_set.original_file + @version_list = Hyrax::VersionListPresenter.new(original ? original.versions.all : []) + @groups = current_user.groups + end + + def actor + @actor ||= Hyrax::Actors::FileSetActor.new(@file_set, current_user) + end + + def attributes + params.fetch(:file_set, {}).except(:files).permit!.dup # use a copy of the hash so that original params stays untouched when interpret_visibility modifies things + end + + def presenter + @presenter ||= begin + _, document_list = search_results(params) + curation_concern = document_list.first + raise CanCan::AccessDenied unless curation_concern + show_presenter.new(curation_concern, current_ability, request) + end + end + + def wants_to_revert? + params.key?(:revision) && params[:revision] != curation_concern.latest_content_version.label + end + + # Override this method to add additional response formats to your local app + def additional_response_formats(_); end + + # This allows us to use the unauthorized and form_permission template in hyrax/base, + # while prefering our local paths. Thus we are unable to just override `self.local_prefixes` + def _prefixes + @_prefixes ||= super + ['hyrax/base'] + end + + def decide_layout + layout = case action_name + when 'show' + '1_column' + else + 'dashboard' + end + File.join(theme, layout) + end + end +end diff --git a/hyrax/app/controllers/hyrax/images_controller.rb b/hyrax/app/controllers/hyrax/images_controller.rb new file mode 100644 index 00000000..c0a19b33 --- /dev/null +++ b/hyrax/app/controllers/hyrax/images_controller.rb @@ -0,0 +1,16 @@ +# Generated via +# `rails generate hyrax:work Image` +module Hyrax + # Generated controller for Image + class ImagesController < ApplicationController + # Adds Hyrax behaviors to the controller. + include Hyrax::WorksControllerBehavior + include Hyrax::BreadcrumbsForWorks + prepend ::DisableApiBehavior + + self.curation_concern_type = ::Image + + # Use this line if you want to use a custom presenter + self.show_presenter = Hyrax::ImagePresenter + end +end diff --git a/hyrax/app/controllers/hyrax/publications_controller.rb b/hyrax/app/controllers/hyrax/publications_controller.rb new file mode 100644 index 00000000..eceeaeeb --- /dev/null +++ b/hyrax/app/controllers/hyrax/publications_controller.rb @@ -0,0 +1,30 @@ +# Generated via +# `rails generate hyrax:work Publication` +module Hyrax + # Generated controller for Publication + class PublicationsController < ApplicationController + # Adds Hyrax behaviors to the controller. + include Hyrax::WorksControllerBehavior + include Hyrax::BreadcrumbsForWorks + include ::ComplexFieldsBehavior + prepend ::DisableApiBehavior + + self.curation_concern_type = ::Publication + + # Use this line if you want to use a custom presenter + self.show_presenter = Hyrax::PublicationPresenter + + def create + safe_params = params['publication'].permit(::Hyrax::PublicationForm.build_permitted_params) + params['publication'] = cleanup_params(safe_params.to_h) + super + end + + def update + safe_params = params['publication'].permit(::Hyrax::PublicationForm.build_permitted_params) + params['publication'] = cleanup_params(safe_params.to_h) + super + end + + end +end diff --git a/hyrax/app/controllers/hyrax/users_controller.rb b/hyrax/app/controllers/hyrax/users_controller.rb new file mode 100644 index 00000000..92783ed1 --- /dev/null +++ b/hyrax/app/controllers/hyrax/users_controller.rb @@ -0,0 +1,11 @@ +require_dependency Hyrax::Engine.config.root.join('app', 'controllers', 'hyrax', 'users_controller.rb').to_s + +class Hyrax::UsersController + prepend ::DisableApiBehavior + + def index + authenticate_user! if Flipflop.hide_users_list? + authorize! :index, ::User + @users = search(params[:uq]) + end +end diff --git a/hyrax/app/controllers/hyrax/works_controller.rb b/hyrax/app/controllers/hyrax/works_controller.rb index 0753b1ed..5c8aa577 100644 --- a/hyrax/app/controllers/hyrax/works_controller.rb +++ b/hyrax/app/controllers/hyrax/works_controller.rb @@ -6,6 +6,8 @@ class WorksController < ApplicationController # Adds Hyrax behaviors to the controller. include Hyrax::WorksControllerBehavior include Hyrax::BreadcrumbsForWorks + prepend ::DisableApiBehavior + self.curation_concern_type = ::Work # Use this line if you want to use a custom presenter diff --git a/hyrax/app/controllers/users/sessions_controller.rb b/hyrax/app/controllers/users/sessions_controller.rb new file mode 100644 index 00000000..f09a2429 --- /dev/null +++ b/hyrax/app/controllers/users/sessions_controller.rb @@ -0,0 +1,9 @@ +module Users + class SessionsController < Devise::SessionsController + def new + self.resource = resource_class.new(sign_in_params) + store_location_for(resource, params[:redirect_to]) + super + end + end +end diff --git a/hyrax/app/controllers/willow_sword/works_controller.rb b/hyrax/app/controllers/willow_sword/works_controller.rb new file mode 100644 index 00000000..05a7fd84 --- /dev/null +++ b/hyrax/app/controllers/willow_sword/works_controller.rb @@ -0,0 +1,31 @@ +require_dependency "willow_sword/application_controller" + +module WillowSword + class WorksController < ApplicationController + before_action :set_work_klass + attr_reader :object, :current_user + + include WillowSword::WorksBehavior + include WillowSword::ProcessRequest + include ::Integrator::Hyrax::WorksBehavior + + # overriding this method so zip files in the payload are unpacked vefore ingest + def bag_request + # The data is processed as a bag + contents_path = File.join(@dir, 'contents') + bag_path = File.join(@dir, 'bag') + unpack_zip_files(contents_path) + # validate or create bag + bag = WillowSword::BagPackage.new(contents_path, bag_path) + @metadata_file = File.join(bag.package.data_dir, WillowSword.config.metadata_filename) + @files = bag.package.bag_files - [@metadata_file] + end + + def unpack_zip_files(contents_path) + zip_files = Dir.glob(File.join(contents_path, '*.zip')) + zip_files.each do |zip_file| + WillowSword::ZipPackage.new(zip_file, contents_path).unzip_file + end + end + end +end diff --git a/hyrax/app/forms/hyrax/dataset_form.rb b/hyrax/app/forms/hyrax/dataset_form.rb new file mode 100644 index 00000000..3e16bf08 --- /dev/null +++ b/hyrax/app/forms/hyrax/dataset_form.rb @@ -0,0 +1,291 @@ +# Generated via +# `rails generate hyrax:work Dataset` +module Hyrax + # Generated form for Dataset + class DatasetForm < Hyrax::Forms::WorkForm + self.model_class = ::Dataset + + self.terms -= [ + # Fields not interested in + :based_near, :contributor, :creator, :date_created, :identifier, :license, + :related_url, :resource_type, :rights_statement, :source, + # Fields interested in, but removing to re-order + :title, :description, :keyword, :language, :publisher, :resource_type, :subject + # Fields that are not displayed + # :import_url, :date_modified, :date_uploaded, :depositor, :bibliographic_citation, + # :date_created, :label, :relative_path + ] + + self.terms += [ + # Adding all fields in order of display in form + :supervisor_approval, + :title, :alternative_title, :description, :keyword, :language, + :publisher, :complex_rights, :subject, :complex_date, :complex_person, + :complex_version, :characterization_methods, :computational_methods, + :complex_organization, + :complex_identifier, + :data_origin, :complex_instrument, :origin_system_provenance, + :properties_addressed, :complex_relation, :specimen_set, + :complex_specimen_type, :synthesis_and_processing, :custom_property + ] + + self.required_fields -= [ + # Fields not interested in + :creator, :keyword, :rights_statement, + # Fields interested in, but removing to re-order + :title] + + self.required_fields += [ + # # Adding all required fields in order of display in form + :supervisor_approval, :title, :data_origin + ] + + def metadata_tab_terms + [ + # Description tab order determined here + :supervisor_approval, + :title, :alternative_title, :data_origin, :description, :keyword, + :specimen_set, :complex_person, + :complex_identifier, # not using this + :complex_date, :complex_rights, :complex_version, :complex_relation, + :custom_property + ] + end + + def method_tab_terms + [ + # Method tab order determined here + :characterization_methods, :computational_methods, + # :origin_system_provenance, # not using this + :properties_addressed, + :synthesis_and_processing + ] + end + + def instrument_tab_terms + [ :complex_instrument ] + end + + def specimen_tab_terms + [ :complex_specimen_type ] + end + + NESTED_ASSOCIATIONS = [:complex_date, :complex_identifier, :complex_instrument, + :complex_organization, :complex_person, :complex_relation, :complex_rights, + :complex_specimen_type, :complex_version, :custom_property].freeze + + protected + + def self.permitted_affiliation_params + [:id, + :_destroy, + { + job_title: [], + complex_organization_attributes: permitted_organization_params, + } + ] + end + + def self.permitted_custom_property_params + [:id, + :_destroy, + { + label: [], + description: [] + } + ] + end + + def self.permitted_date_params + [:id, + :_destroy, + { + date: [], + description: [] + } + ] + end + + def self.permitted_desc_id_params + [:id, + :_destroy, + { + description: [], + complex_identifier_attributes: permitted_identifier_params, + } + ] + end + + def self.permitted_identifier_params + [:id, + :_destroy, + { + identifier: [], + scheme: [], + label: [] + } + ] + end + + def self.permitted_instrument_params + [:id, + :_destroy, + { + alternative_title: [], + complex_date_attributes: permitted_date_params, + description: [], + complex_identifier_attributes: permitted_identifier_params, + instrument_function_attributes: permitted_instrument_function_params, + manufacturer_attributes: permitted_organization_params, + model_number: [], + complex_person_attributes: permitted_person_params, + managing_organization_attributes: permitted_organization_params, + title: [] + } + ] + end + + def self.permitted_instrument_function_params + [:id, + :_destroy, + { + column_number: [], + category: [], + sub_category: [], + description: [] + } + ] + end + + def self.permitted_material_type_params + [:id, + :_destroy, + { + material_type: [], + description: [], + complex_identifier_attributes: permitted_identifier_params, + material_sub_type: [] + } + ] + end + + def self.permitted_organization_params + [:id, + :_destroy, + { + organization: [], + sub_organization: [], + purpose: [], + complex_identifier_attributes: permitted_identifier_params, + } + ] + end + + def self.permitted_person_params + [:id, + :_destroy, + { + name: [], + role: [], + complex_affiliation_attributes: permitted_affiliation_params, + complex_identifier_attributes: permitted_identifier_params, + uri: [] + } + ] + end + + def self.permitted_purchase_record_params + [:id, + :_destroy, + { + date: [], + complex_identifier_attributes: permitted_identifier_params, + supplier_attributes: permitted_organization_params, + manufacturer_attributes: permitted_organization_params, + purchase_record_item: [], + title: [] + } + ] + end + + def self.permitted_relation_params + [:id, + :_destroy, + { + title: [], + url: [], + complex_identifier_attributes: permitted_identifier_params, + relationship: [] + } + ] + end + + def self.permitted_rights_params + [:id, + :_destroy, + { + date: [], + rights: [] + } + ] + end + + def self.permitted_specimen_type_params + [:id, + :_destroy, + { + complex_chemical_composition_attributes: permitted_desc_id_params, + complex_crystallographic_structure_attributes: permitted_desc_id_params, + description: [], + complex_identifier_attributes: permitted_identifier_params, + complex_material_type_attributes: permitted_material_type_params, + complex_purchase_record_attributes: permitted_purchase_record_params, + complex_shape_attributes: permitted_desc_id_params, + complex_state_of_matter_attributes: permitted_desc_id_params, + complex_structural_feature_attributes: permitted_structural_feature_params, + title: [] + } + ] + end + + def self.permitted_structural_feature_params + [:id, + :_destroy, + { + category: [], + description: [], + complex_identifier_attributes: permitted_identifier_params, + sub_category: [] + } + ] + end + + def self.permitted_version_params + [:id, + :_destroy, + { + date: [], + description: [], + identifier: [], + version: [] + } + ] + end + + def self.build_permitted_params + permitted = super + permitted << { complex_date_attributes: permitted_date_params } + permitted << { complex_identifier_attributes: permitted_identifier_params } + permitted << { complex_instrument_attributes: permitted_instrument_params } + permitted << { complex_person_attributes: permitted_person_params } + permitted << { complex_organization_attributes: permitted_organization_params } + permitted << { complex_relation_attributes: permitted_relation_params } + permitted << { complex_rights_attributes: permitted_rights_params } + permitted << { complex_specimen_type_attributes: permitted_specimen_type_params } + permitted << { complex_version_attributes: permitted_version_params } + permitted << { custom_property_attributes: permitted_custom_property_params } + permitted << :member_of_collection_ids + permitted << :find_child_work + end + end +end diff --git a/hyrax/app/forms/hyrax/image_form.rb b/hyrax/app/forms/hyrax/image_form.rb new file mode 100644 index 00000000..35b254d4 --- /dev/null +++ b/hyrax/app/forms/hyrax/image_form.rb @@ -0,0 +1,133 @@ +# Generated via +# `rails generate hyrax:work Image` +module Hyrax + # Generated form for Image + class ImageForm < Hyrax::Forms::WorkForm + self.model_class = ::Image + + self.terms -= [ + # Fields not interested in + :based_near, :contributor, :creator, :date_created, :identifier, :license, + :rights_statement, :related_url, :source, + # Fields interested in, but removing to re-order + :title, :description, :keyword, :language, :publisher, :resource_type, :subject + # Fields that are not displayed + # :import_url, :date_modified, :date_uploaded, :depositor, :bibliographic_citation, + # :date_created, :label, :relative_path + ] + + self.terms += [ + # Adding all fields in order of display in form + :title, :alternative_title, :description, :keyword, :language, + :publisher, :resource_type, :complex_rights, :subject, + :complex_date, :complex_identifier, :complex_person, :complex_version, + :status, :instrument, :specimen_set, :complex_relation, :custom_property + ] + + self.required_fields -= [ + # Fields not interested in + :creator, :keyword, :rights_statement, + # Fields interested in, but removing to re-order + :title] + + self.required_fields += [ + # # Adding all required fields in order of display in form + :title + ] + + NESTED_ASSOCIATIONS = [:complex_date, :complex_identifier, :complex_person, + :complex_rights, :complex_version, :complex_relation, :custom_property].freeze + + protected + + def self.permitted_date_params + [:id, + :_destroy, + { + date: [], + description: [] + } + ] + end + + def self.permitted_identifier_params + [:id, + :_destroy, + { + identifier: [], + scheme: [], + label: [] + } + ] + end + + def self.permitted_person_params + [:id, + :_destroy, + { + name: [], + role: [], + affiliation: [], + complex_identifier_attributes: permitted_identifier_params, + uri: [] + } + ] + end + + def self.permitted_rights_params + [:id, + :_destroy, + { + date: [], + rights: [] + } + ] + end + + def self.permitted_version_params + [:id, + :_destroy, + { + date: [], + description: [], + identifier: [], + version: [] + } + ] + end + + def self.permitted_relation_params + [:id, + :_destroy, + { + title: [], + url: [], + complex_identifier_attributes: permitted_identifier_params, + relationship: [] + } + ] + end + + def self.permitted_custom_property_params + [:id, + :_destroy, + { + label: [], + description: [] + } + ] + end + + def self.build_permitted_params + permitted = super + permitted << { complex_date_attributes: permitted_date_params } + permitted << { complex_identifier_attributes: permitted_identifier_params } + permitted << { complex_person_attributes: permitted_person_params } + permitted << { complex_rights_attributes: permitted_rights_params } + permitted << { complex_version_attributes: permitted_version_params } + permitted << { complex_relation_attributes: permitted_relation_params } + permitted << { custom_property_attributes: permitted_custom_property_params } + end + + end +end diff --git a/hyrax/app/forms/hyrax/publication_form.rb b/hyrax/app/forms/hyrax/publication_form.rb new file mode 100644 index 00000000..f672a534 --- /dev/null +++ b/hyrax/app/forms/hyrax/publication_form.rb @@ -0,0 +1,164 @@ +# Generated via +# `rails generate hyrax:work Publication` +module Hyrax + # Generated form for Publication + class PublicationForm < Hyrax::Forms::WorkForm + self.model_class = ::Publication + self.terms -= [ + # Fields not interested in + :based_near, :contributor, :creator, :date_created, :identifier, :license, + :rights_statement, :related_url, :source, + # Fields interested in, but removing to re-order + :title, :description, :keyword, :language, :publisher, :resource_type, + :subject + # Fields that are not displayed + # :import_url, :date_modified, :date_uploaded, :depositor, :bibliographic_citation, + # :date_created, :label, :relative_path + ] + + self.terms += [ + # Adding all fields in order of display in form + :supervisor_approval, + :title, :alternative_title, :complex_person, :description, :keyword, + :publisher, :resource_type, :complex_rights, + :complex_date, :complex_identifier, :complex_source, :complex_version, + :complex_event, :language + ] + + self.required_fields -= [ + # Fields not interested in + :creator, :keyword, :rights_statement, + # Fields interested in, but removing to re-order + :title] + + self.required_fields += [ + # Adding all required fields in order of display in form + :supervisor_approval, :title, :resource_type + ] + + NESTED_ASSOCIATIONS = [:complex_date, :complex_identifier, + :complex_person, :complex_rights, :complex_version, :complex_event, :complex_source].freeze + + protected + + def self.permitted_affiliation_params + [:id, + :_destroy, + { + job_title: [], + complex_organization_attributes: permitted_organization_params, + } + ] + end + + def self.permitted_date_params + [:id, + :_destroy, + { + date: [], + description: [] + } + ] + end + + def self.permitted_identifier_params + [:id, + :_destroy, + { + identifier: [], + scheme: [], + label: [] + } + ] + end + + def self.permitted_organization_params + [:id, + :_destroy, + { + organization: [], + sub_organization: [], + purpose: [], + complex_identifier_attributes: permitted_identifier_params, + } + ] + end + + def self.permitted_person_params + [:id, + :_destroy, + { + name: [], + role: [], + complex_affiliation_attributes: permitted_affiliation_params, + complex_identifier_attributes: permitted_identifier_params, + uri: [] + } + ] + end + + def self.permitted_rights_params + [:id, + :_destroy, + { + date: [], + rights: [] + } + ] + end + + def self.permitted_version_params + [:id, + :_destroy, + { + date: [], + description: [], + identifier: [], + version: [] + } + ] + end + + def self.permitted_event_params + [:id, + :_destroy, + { + title: [], + place: [], + start_date: [], + end_date: [], + invitation_status: [] + } + ] + end + + def self.permitted_source_params + [:id, + :_destroy, + { + alternative_title: [], + end_page: [], + issue: [], + sequence_number: [], + start_page: [], + title: [], + total_number_of_pages: [], + volume: [] + } + ] + end + + def self.build_permitted_params + permitted = super + permitted << { complex_date_attributes: permitted_date_params } + permitted << { complex_identifier_attributes: permitted_identifier_params } + permitted << { complex_person_attributes: permitted_person_params } + permitted << { complex_rights_attributes: permitted_rights_params } + permitted << { complex_version_attributes: permitted_version_params } + permitted << { complex_event_attributes: permitted_event_params } + permitted << { complex_source_attributes: permitted_source_params } + permitted << :member_of_collection_ids + permitted << :find_child_work + end + end +end diff --git a/hyrax/app/helpers/hyrax/citations_behaviors/formatters/authors_list_apa.rb b/hyrax/app/helpers/hyrax/citations_behaviors/formatters/authors_list_apa.rb new file mode 100644 index 00000000..4f596b74 --- /dev/null +++ b/hyrax/app/helpers/hyrax/citations_behaviors/formatters/authors_list_apa.rb @@ -0,0 +1,26 @@ +# override - hyrax-2.4.1 +module Hyrax + module CitationsBehaviors + module Formatters + module AuthorsListApa + + def format_authors(authors_list = []) + return '' if authors_list.blank? + authors_list = Array.wrap(authors_list).collect { |name| abbreviate_name(surname_first(name)).strip } + # prevent errors if no authors have been specified + text = '' + text << authors_list.first if authors_list.first + authors_list[1..-1].each do |author| + if author == authors_list.last # last + text << ", & " << author + else # all others + text << ", " << author + end + end + text << "." unless text =~ /\.$/ + text + end + end + end + end +end \ No newline at end of file diff --git a/hyrax/app/helpers/hyrax/citations_behaviors/formatters/open_url_formatter.rb b/hyrax/app/helpers/hyrax/citations_behaviors/formatters/open_url_formatter.rb new file mode 100644 index 00000000..879dca32 --- /dev/null +++ b/hyrax/app/helpers/hyrax/citations_behaviors/formatters/open_url_formatter.rb @@ -0,0 +1,41 @@ +# override - hyrax-2.6.0 + +module Hyrax + module CitationsBehaviors + module Formatters + class OpenUrlFormatter < BaseFormatter + def format(work) + export_text = [] + export_text << "url_ver=Z39.88-2004&ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Adc&rfr_id=info%3Asid%2Fblacklight.rubyforge.org%3Agenerator" + FIELD_MAP.each do |element, kev| + next unless work.respond_to?(element) + # ensure the abstract is not visible unless the user is authorised to view it + next if element == :description && view_context.cannot?(:read_abstract, work.model_name.name.constantize) + values = work.send(element) + Array.wrap(values).each do |value| + next if value.blank? + export_text << "rft.#{kev}=#{CGI.escape(value.to_s)}" + end + end + export_text.join('&') if export_text.present? + end + + FIELD_MAP = { + title: 'title', + creator: 'creator', + subject: 'subject', + description: 'description', + publisher: 'publisher', + contributor: 'contributor', + date_created: 'date', + resource_type: 'format', + identifier: 'identifier', + language: 'language', + keyword: 'relation', + based_near: 'coverage', + license: 'license' + }.freeze + end + end + end +end diff --git a/hyrax/app/helpers/hyrax/citations_behaviors/name_behavior.rb b/hyrax/app/helpers/hyrax/citations_behaviors/name_behavior.rb new file mode 100644 index 00000000..83960c54 --- /dev/null +++ b/hyrax/app/helpers/hyrax/citations_behaviors/name_behavior.rb @@ -0,0 +1,55 @@ +module Hyrax + module CitationsBehaviors + module NameBehavior + include Hyrax::CitationsBehaviors::CommonBehavior + # return all unique authors with end punctuation removed + def author_list(work) + all_authors(work) { |author| clean_end_punctuation(CGI.escapeHTML(author)) } + end + + # return all unique authors of a work or nil if none + # nims override to retrieve nested properties + def all_authors(work, &block) + authors = work.solr_document['complex_person_author_tesim'] || [] + block_given? ? authors.map(&block) : authors + end + + def given_name_first(name) + name = clean_end_punctuation(name) + return name unless name =~ /,/ + temp_name = name.split(/,\s*/) + temp_name.last + " " + temp_name.first + end + + # TODO: this logic does not correctly handle middle names: 'First Middle LAST' --> 'Middle LAST, First' + def surname_first(name) + name = name.join('') if name.is_a? Array + # make sure we handle "Cher" correctly + return name if name.include?(',') + name_segments = name.split(' ') + given_name = name_segments.first + surnames = name_segments[1..-1] + + if surnames.any? + "#{surnames.join(' ')}, #{given_name}" + else + given_name + end + end + + # TODO: this logic does not correctly handle middle names: 'First Middle LAST' --> 'Middle LAST, F.' + def abbreviate_name(name) + abbreviated_name = '' + name = name.join('') if name.is_a? Array + + # make sure we handle "Cher" correctly + return name unless name.include?(' ') || name.include?(',') + name = surname_first(name) + name_segments = name.split(/,\s*/) + abbreviated_name << name_segments.first + abbreviated_name << ", #{name_segments.last.first}" if name_segments[1] + abbreviated_name << "." + end + end + end +end \ No newline at end of file diff --git a/hyrax/app/helpers/hyrax/citations_behaviors/publication_behavior.rb b/hyrax/app/helpers/hyrax/citations_behaviors/publication_behavior.rb new file mode 100644 index 00000000..ddc97214 --- /dev/null +++ b/hyrax/app/helpers/hyrax/citations_behaviors/publication_behavior.rb @@ -0,0 +1,71 @@ +# override - hyrax-2.4.1 +require 'json' +module Hyrax + module CitationsBehaviors + module PublicationBehavior + include Hyrax::CitationsBehaviors::CommonBehavior + + # nims override to add doi + def setup_doi(presenter) + ci = presenter.complex_identifier + if presenter.complex_identifier.is_a?(Array) + ci = presenter.complex_identifier.first + end + JSON.parse(ci). + select{|i| i["scheme"].any?{|s| s =~/doi/i} }. + pluck('identifier'). + flatten. + sort. + join('. ') + rescue JSON::ParserError # catch dodgy json + nil + end + + # nims override to retrieve nested properties + def setup_pub_date(presenter) + pub_date = presenter.solr_document['complex_date_published_ssm'].try(:first) + return nil if pub_date.nil? + first_date = CGI.escapeHTML(pub_date) + if first_date.present? + first_date = CGI.escapeHTML(first_date) + date_value = first_date.gsub(/[^0-9|n\.d\.]/, "") + date_value = date_value.reverse[0, 4].reverse unless date_value.nil? + return nil if date_value.nil? + end + clean_end_punctuation(date_value) if date_value + end + + # @param [Hyrax::PublicationPresenter] presenter + # nims override to retrieve place + def setup_pub_place(presenter) + return '' unless presenter.respond_to?(:place) + return '' if presenter.place.blank? + # place is a singular property, but returns here as an array (?) + presenter.place.is_a?(String) ? presenter.place : presenter.place&.first + end + + def setup_pub_publisher(presenter) + presenter.publisher&.first + end + + def setup_pub_info(presenter, include_date = false) + pub_info = "" + if (place = setup_pub_place(presenter)) + pub_info << CGI.escapeHTML(place) + end + if (publisher = setup_pub_publisher(presenter)) + pub_info << ": " << CGI.escapeHTML(publisher) + end + + pub_date = include_date ? setup_pub_date(presenter) : nil + pub_info << ", " << pub_date unless pub_date.nil? + # nims override to add doi + pub_doi = setup_doi(presenter) + pub_info << ". " << pub_doi unless pub_doi.nil? + # end nims override to add doi + pub_info.strip! + pub_info.blank? ? nil : pub_info + end + end + end +end diff --git a/hyrax/app/helpers/hyrax/iiif_helper.rb b/hyrax/app/helpers/hyrax/iiif_helper.rb new file mode 100644 index 00000000..49f6c782 --- /dev/null +++ b/hyrax/app/helpers/hyrax/iiif_helper.rb @@ -0,0 +1,22 @@ +module Hyrax + module IiifHelper + # @todo remove after upgrade to Hyrax 3.x + + def iiif_viewer_display(work_presenter, locals = {}) + render iiif_viewer_display_partial(work_presenter), + locals.merge(presenter: work_presenter) + end + + def iiif_viewer_display_partial(work_presenter) + 'hyrax/base/iiif_viewers/' + work_presenter.iiif_viewer.to_s + end + + def universal_viewer_base_url + "#{request&.base_url}/uv/uv.html" + end + + def universal_viewer_config_url + "#{request&.base_url}/uv/uv-config.json" + end + end +end diff --git a/hyrax/app/helpers/hyrax/nims_file_set_helper.rb b/hyrax/app/helpers/hyrax/nims_file_set_helper.rb new file mode 100644 index 00000000..07419026 --- /dev/null +++ b/hyrax/app/helpers/hyrax/nims_file_set_helper.rb @@ -0,0 +1,30 @@ +# special extension of the default FileSetHelper to cater for CSV files +module Hyrax + module NimsFileSetHelper + include Hyrax::FileSetHelper + + def nims_media_display(presenter, locals = {}) + render nims_media_display_partial(presenter), + locals.merge(file_set: presenter) + end + + def nims_media_display_partial(presenter) + 'hyrax/file_sets/media_display/' + + if presenter.image? + 'image' + elsif presenter.video? + 'video' + elsif presenter.audio? + 'audio' + elsif presenter.pdf? + 'pdf' + elsif presenter.office_document? + 'office_document' + elsif presenter.csv? + 'csv' + else + 'default' + end + end + end +end diff --git a/hyrax/app/helpers/hyrax_helper.rb b/hyrax/app/helpers/hyrax_helper.rb index d7e853b9..dd571241 100644 --- a/hyrax/app/helpers/hyrax_helper.rb +++ b/hyrax/app/helpers/hyrax_helper.rb @@ -2,4 +2,29 @@ module HyraxHelper include ::BlacklightHelper include Hyrax::BlacklightOverride include Hyrax::HyraxHelperBehavior + + def available_translations + { + # 'de' => 'Deutsch', + 'en' => 'English', + # 'es' => 'Español', + # 'fr' => 'Français', + # 'it' => 'Italiano', + # 'pt-BR' => 'Português do Brasil', + # 'zh' => '中文' + } + end + + def link_to_profile(args) + user_or_key = args.is_a?(Hash) ? args[:value].first : args + user = case user_or_key + when User + user_or_key + when String + ::User.find_by_user_key(user_or_key) + end + return user_or_key if user.nil? + text = user.respond_to?(:name) ? user.name : user_or_key + link_to text, Hyrax::Engine.routes.url_helpers.user_path(user.user_identifier) + end end diff --git a/hyrax/app/indexers/.keep b/hyrax/app/indexers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/hyrax/app/indexers/complex_field/chemical_composition_indexer.rb b/hyrax/app/indexers/complex_field/chemical_composition_indexer.rb new file mode 100644 index 00000000..c8080e6f --- /dev/null +++ b/hyrax/app/indexers/complex_field/chemical_composition_indexer.rb @@ -0,0 +1,36 @@ +module ComplexField + module ChemicalCompositionIndexer + def generate_solr_document + super.tap do |solr_doc| + index_chemical_composition(solr_doc) + end + end + + def index_chemical_composition(solr_doc) + object.complex_specimen_type.each do |st| + # description as complex_chemical_composition searchable + desc = st.complex_chemical_composition.map { |c| c.description.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_chemical_composition', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << desc + solr_doc[fld_name].flatten! + st.complex_chemical_composition.each do |cc| + cc.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('complex_chemical_composition_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + end + end + end + + def self.chemical_composition_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_chemical_composition', :stored_searchable) + fields << Solrizer.solr_name('complex_chemical_composition_identifier', :symbol) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/crystallographic_structure_indexer.rb b/hyrax/app/indexers/complex_field/crystallographic_structure_indexer.rb new file mode 100644 index 00000000..2b798491 --- /dev/null +++ b/hyrax/app/indexers/complex_field/crystallographic_structure_indexer.rb @@ -0,0 +1,36 @@ +module ComplexField + module CrystallographicStructureIndexer + def generate_solr_document + super.tap do |solr_doc| + index_crystallographic_structure(solr_doc) + end + end + + def index_crystallographic_structure(solr_doc) + object.complex_specimen_type.each do |st| + # description as complex_crystallographic_structure searchable + desc = st.complex_crystallographic_structure.map { |c| c.description.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_crystallographic_structure', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << desc + solr_doc[fld_name].flatten! + st.complex_crystallographic_structure.each do |cs| + cs.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('complex_crystallographic_structure_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + end + end + end + + def self.crystallographic_structure_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_crystallographic_structure', :stored_searchable) + fields << Solrizer.solr_name('complex_crystallographic_structure_identifier', :symbol) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/custom_property_indexer.rb b/hyrax/app/indexers/complex_field/custom_property_indexer.rb new file mode 100644 index 00000000..94375927 --- /dev/null +++ b/hyrax/app/indexers/complex_field/custom_property_indexer.rb @@ -0,0 +1,46 @@ +module ComplexField + module CustomPropertyIndexer + def generate_solr_document + super.tap do |solr_doc| + index_custom_property(solr_doc) + end + end + + def index_custom_property(solr_doc) + # json object as custom_property displayable + solr_doc[Solrizer.solr_name('custom_property', :displayable)] = object.custom_property.to_json + # description as custom_property searchable + property = object.custom_property.map { |c| c.description.reject(&:blank?) } + solr_doc[Solrizer.solr_name('custom_property', :stored_searchable)] = property + object.custom_property.each do |c| + unless (c.label.first.blank? or c.description.first.blank?) + # description as custom property (additional metadata) label searchable + fld_name = Solrizer.solr_name("custom_property_#{c.label.first.downcase.tr(' ', '_')}", :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << c.description.reject(&:blank?) + solr_doc[fld_name].flatten! + # description as custom property (additional metadata) label facetable + fld_name = Solrizer.solr_name("custom_property_#{c.label.first.downcase.tr(' ', '_')}", :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << c.description.reject(&:blank?) + solr_doc[fld_name].flatten! + end + end + end + + def self.custom_property_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('custom_property', :stored_searchable) + fields + end + + def self.custom_property_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('custom_property', :displayable) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/date_indexer.rb b/hyrax/app/indexers/complex_field/date_indexer.rb new file mode 100644 index 00000000..e2c6c8cb --- /dev/null +++ b/hyrax/app/indexers/complex_field/date_indexer.rb @@ -0,0 +1,115 @@ +module ComplexField + module DateIndexer + def generate_solr_document + super.tap do |solr_doc| + index_date(solr_doc) + end + end + + def index_date(solr_doc) + return if object.complex_date.blank? + # json object as complex_date displayable + solr_doc[Solrizer.solr_name('complex_date', :displayable)] = object.complex_date.to_json + # date as complex_date searchable + dates = object.complex_date.map { |d| d.date.reject(&:blank?) }.flatten + # cope with just a year being supplied + begin + dates_utc = dates.map{|d| d.tr('0-9a-zA-Z','0-9a-zA-Z')}.map { |d| d.length <= 4 ? DateTime.strptime(d, '%Y').utc.iso8601 : DateTime.parse(d).utc.iso8601 } unless dates.blank? + rescue ArgumentError + dates_utc = dates.map{|d| d.tr('0-9a-zA-Z','0-9a-zA-Z')}.map { |d| DateTime.parse("#{d}-01").utc.iso8601 } unless dates.blank? + end + solr_doc[Solrizer.solr_name('complex_date', :stored_searchable, type: :date)] = dates_utc unless dates.blank? + solr_doc[Solrizer.solr_name('complex_date', :dateable)] = dates_utc unless dates.blank? + # add year + years = dates_utc.map {|d| DateTime.parse(d).strftime("%Y")} + solr_doc[Solrizer.solr_name('complex_year', :stored_searchable)] = years unless dates.blank? + solr_doc[Solrizer.solr_name('complex_year', :facetable)] = years unless dates.blank? + object.complex_date.each do |d| + next if d.date.reject(&:blank?).blank? + label = 'other' + unless d.description.blank? + # Finding its display label for indexing + term = DateService.new.find_by_id(d.description.first) + label = term['label'] if term.any? + end + label = label.downcase.tr(' ', '_') + # Not indexing date as sortbale as it needs to be single valued + # fld_name = Solrizer.solr_name("complex_date_#{label.downcase.tr(' ', '_')}", :stored_sortable, type: :date) + # solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + # solr_doc[fld_name] << DateTime.parse(d.date.reject(&:blank?).first).utc.iso8601 + # solr_doc[fld_name] = solr_doc[fld_name].uniq.first + # date as complex_date_type dateable + vals = d.date.reject(&:blank?) + fld_name = Solrizer.solr_name("complex_date_#{label}", :dateable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + begin + dates_utc = vals.map{|d| d.tr('0-9a-zA-Z','0-9a-zA-Z')}.map { |d| d.length <= 4 ? DateTime.strptime(d, '%Y').utc.iso8601 : DateTime.parse(d).utc.iso8601 } unless dates.blank? + rescue ArgumentError + dates_utc = vals.map{|d| d.tr('0-9a-zA-Z','0-9a-zA-Z')}.map { |d| DateTime.parse("#{d}-01").utc.iso8601 } unless dates.blank? + end + solr_doc[fld_name] << dates_utc unless dates_utc.blank? + solr_doc[fld_name].flatten! + # Add years + year_fld = Solrizer.solr_name("complex_year_#{label}", :facetable) + years = dates_utc.map {|d| DateTime.parse(d).strftime("%Y")} + solr_doc[year_fld] = [] unless solr_doc.include?(year_fld) + solr_doc[year_fld] << years unless years.blank? + solr_doc[year_fld].flatten! + # date as complex_date_type displayable + fld_name = Solrizer.solr_name("complex_date_#{label}", :displayable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + end + end + + def self.date_facet_fields + # solr fields that will be treated as facets + fields = [] + # change all dates to years + fields << Solrizer.solr_name('complex_year_accepted', :facetable) + fields << Solrizer.solr_name('complex_year_available', :facetable) + fields << Solrizer.solr_name('complex_year_copyrighted', :facetable) + fields << Solrizer.solr_name('complex_year_collected', :facetable) + fields << Solrizer.solr_name('complex_year_created', :facetable) + fields << Solrizer.solr_name('complex_year_issued', :facetable) + fields << Solrizer.solr_name('complex_year_published', :facetable) + fields << Solrizer.solr_name('complex_year_submitted', :facetable) + fields << Solrizer.solr_name('complex_year_updated', :facetable) + fields << Solrizer.solr_name('complex_year_valid', :facetable) + fields << Solrizer.solr_name('complex_year_processed', :facetable) + fields << Solrizer.solr_name('complex_year_purchased', :facetable) + fields << Solrizer.solr_name('complex_year_other', :facetable) + fields + end + + def self.date_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_date', :stored_searchable, type: :date) + fields << Solrizer.solr_name('complex_year', :stored_searchable) + fields + end + + def self.date_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_date_accepted', :displayable) + fields << Solrizer.solr_name('complex_date_available', :displayable) + fields << Solrizer.solr_name('complex_date_copyrighted', :displayable) + fields << Solrizer.solr_name('complex_date_collected', :displayable) + fields << Solrizer.solr_name('complex_date_created', :displayable) + fields << Solrizer.solr_name('complex_date_issued', :displayable) + fields << Solrizer.solr_name('complex_date_published', :displayable) + fields << Solrizer.solr_name('complex_date_submitted', :displayable) + fields << Solrizer.solr_name('complex_date_updated', :displayable) + fields << Solrizer.solr_name('complex_date_valid', :displayable) + fields << Solrizer.solr_name('complex_date_processed', :displayable) + fields << Solrizer.solr_name('complex_date_purchased', :displayable) + fields << Solrizer.solr_name('complex_date_other', :displayable) + fields + end + + end +end + diff --git a/hyrax/app/indexers/complex_field/event_indexer.rb b/hyrax/app/indexers/complex_field/event_indexer.rb new file mode 100644 index 00000000..fa994620 --- /dev/null +++ b/hyrax/app/indexers/complex_field/event_indexer.rb @@ -0,0 +1,38 @@ +module ComplexField + module EventIndexer + def generate_solr_document + super.tap do |solr_doc| + index_event(solr_doc) + end + end + + def index_event(solr_doc) + solr_doc[Solrizer.solr_name('complex_event', :displayable)] = object.complex_event.to_json + solr_doc[Solrizer.solr_name('complex_event_title', :stored_searchable)] = object.complex_event.map { |r| r.title.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_event_place', :stored_searchable)] = object.complex_event.map { |r| r.place.reject(&:blank?).first } + end + + def self.event_facet_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('complex_event', :facetable) + fields + end + + def self.event_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_event_title', :stored_searchable) + fields << Solrizer.solr_name('complex_event_place', :stored_searchable) + fields + end + + def self.event_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_event', :displayable) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/identifier_indexer.rb b/hyrax/app/indexers/complex_field/identifier_indexer.rb new file mode 100644 index 00000000..16878528 --- /dev/null +++ b/hyrax/app/indexers/complex_field/identifier_indexer.rb @@ -0,0 +1,37 @@ +module ComplexField + module IdentifierIndexer + def generate_solr_document + super.tap do |solr_doc| + index_identifier(solr_doc) + end + end + + def index_identifier(solr_doc) + solr_doc[Solrizer.solr_name('complex_identifier', :symbol)] = object.complex_identifier.map { |i| i.identifier.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_identifier', :displayable)] = object.complex_identifier.to_json + object.complex_identifier.each do |i| + unless i.scheme.blank? || i.identifier.blank? + fld_name = Solrizer.solr_name("complex_identifier_#{i.scheme.reject(&:blank?).first.downcase.tr(' ', '_')}", :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << i.identifier.reject(&:blank?) + solr_doc[fld_name].flatten! + end + end + end + + def self.identifier_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_identifier', :symbol) + fields + end + + def self.identifier_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_identifier', :displayable) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/instrument_indexer.rb b/hyrax/app/indexers/complex_field/instrument_indexer.rb new file mode 100644 index 00000000..806510bd --- /dev/null +++ b/hyrax/app/indexers/complex_field/instrument_indexer.rb @@ -0,0 +1,159 @@ +module ComplexField + module InstrumentIndexer + def generate_solr_document + super.tap do |solr_doc| + index_instrument(solr_doc) + end + end + + def index_instrument(solr_doc) + solr_doc[Solrizer.solr_name('complex_instrument', :displayable)] = object.complex_instrument.to_json + solr_doc[Solrizer.solr_name('instrument_title', :stored_searchable)] = object.complex_instrument.map { |i| i.title.reject(&:blank?) }.flatten! + # use the instrument title for the complex_instrument_sim facet + solr_doc[Solrizer.solr_name('complex_instrument', :facetable)] = object.complex_instrument.map { |i| i.title.reject(&:blank?) }.flatten! + + fld_name = Solrizer.solr_name('instrument_title', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + vals = object.complex_instrument.map { |i| i.title.reject(&:blank?) } + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + + solr_doc[Solrizer.solr_name('instrument_alternative_title', :stored_searchable)] = object.complex_instrument.map { |i| i.alternative_title.reject(&:blank?) }.flatten! + solr_doc[Solrizer.solr_name('instrument_description', :stored_searchable)] = object.complex_instrument.map { |i| i.description.reject(&:blank?) }.flatten! + solr_doc[Solrizer.solr_name('instrument_model_number', :stored_searchable)] = object.complex_instrument.map { |i| i.model_number.reject(&:blank?) }.flatten! + solr_doc[Solrizer.solr_name('instrument_model_number', :facetable)] = object.complex_instrument.map { |i| i.model_number.reject(&:blank?) }.flatten! + object.complex_instrument.each do |i| + i.complex_date.each do |d| + dt = d.date.reject(&:blank?).first + next if dt.blank? + desc = d.description.first + label = 'processed' + label = DateService.new.label(d.description.first) unless desc.blank? + label = label.downcase.tr(' ', '_') + # date dateable + fld_name = Solrizer.solr_name("complex_date_#{label}", :dateable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << d.date.reject(&:blank?).map { |dt| DateTime.parse(dt).utc.iso8601 } + solr_doc[fld_name].flatten! + # date displayable + fld_name = Solrizer.solr_name("complex_date_#{label}", :displayable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << d.date.reject(&:blank?) + solr_doc[fld_name].flatten! + end + i.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('instrument_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + i.manufacturer.each do |org| + fld_name = Solrizer.solr_name('instrument_manufacturer', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('instrument_manufacturer', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('instrument_manufacturer_sub_organization', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.sub_organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('instrument_manufacturer_sub_organization', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.sub_organization.reject(&:blank?) + solr_doc[fld_name].flatten! + end + i.complex_person.each do |pn| + person_name = pn.name.reject(&:blank?) + person_name = (pn.first_name + pn.last_name).reject(&:blank?).join(' ') if person_name.blank? + next if person_name.blank? + label = 'operator' + label = pn.role.first unless pn.role.blank? + label = label.downcase.tr(' ', '_') + fld_name = Solrizer.solr_name("complex_person_#{label}", :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << person_name + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name("complex_person_#{label}", :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << person_name + solr_doc[fld_name].flatten! + # Affiliation + pn.complex_affiliation.each do |ca| + ca.complex_organization.each do |co| + vals = co.organization.reject(&:blank?) + fld_name = Solrizer.solr_name("complex_person_#{label}_organization", :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + fld_name = Solrizer.solr_name("complex_person_#{label}_organization", :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + vals = co.sub_organization.reject(&:blank?) + fld_name = Solrizer.solr_name("complex_person_#{label}_sub_organization", :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + fld_name = Solrizer.solr_name("complex_person_#{label}_sub_organization", :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + end + end + end + i.managing_organization.each do |org| + fld_name = Solrizer.solr_name('instrument_managing_organization', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('instrument_managing_organization', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('instrument_managing_sub_organization', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.sub_organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('instrument_managing_sub_organization', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.sub_organization.reject(&:blank?) + solr_doc[fld_name].flatten! + end + end + end + + def self.instrument_facet_fields + # solr fields that will be treated as facets + fields = [] + #fields << Solrizer.solr_name('instrument_title', :facetable) + fields << Solrizer.solr_name('instrument_manufacturer', :facetable) + fields << Solrizer.solr_name('instrument_manufacturer_sub_organization', :facetable) + fields << Solrizer.solr_name('instrument_model_number', :facetable) + fields << Solrizer.solr_name('instrument_managing_organization', :facetable) + fields << Solrizer.solr_name('instrument_managing_sub_organization', :facetable) + fields + end + + def self.instrument_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('instrument_title', :stored_searchable) + fields << Solrizer.solr_name('instrument_alternative_title', :stored_searchable) + fields << Solrizer.solr_name('instrument_description', :stored_searchable) + fields << Solrizer.solr_name('instrument_manufacturer', :stored_searchable) + fields << Solrizer.solr_name('instrument_manufacturer_sub_organization', :stored_searchable) + fields << Solrizer.solr_name('instrument_managing_organization', :stored_searchable) + fields << Solrizer.solr_name('instrument_managing_sub_organization', :stored_searchable) + fields + end + + def self.instrument_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_instrument', :displayable) + fields + end + end +end diff --git a/hyrax/app/indexers/complex_field/material_type_indexer.rb b/hyrax/app/indexers/complex_field/material_type_indexer.rb new file mode 100644 index 00000000..4e46e1dd --- /dev/null +++ b/hyrax/app/indexers/complex_field/material_type_indexer.rb @@ -0,0 +1,69 @@ +module ComplexField + module MaterialTypeIndexer + def generate_solr_document + super.tap do |solr_doc| + index_material_type(solr_doc) + end + end + + def index_material_type(solr_doc) + object.complex_specimen_type.each do |st| + # material_type as complex_material_type searchable + vals = st.complex_material_type.map { |c| c.material_type.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_material_type', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # material_type as complex_material_type facetable + fld_name = Solrizer.solr_name('complex_material_type', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # description as complex_material_type_description searchable + vals = st.complex_material_type.map { |c| c.description.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_material_type_description', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # material_sub_type as complex_material_sub_type searchable + vals = st.complex_material_type.map { |c| c.material_sub_type.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_material_sub_type', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # material_sub_type as complex_material_sub_type facetable + fld_name = Solrizer.solr_name('complex_material_sub_type', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # identifier + st.complex_material_type.each do |cc| + cc.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('complex_material_type_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + end + end + end + + def self.material_type_facet_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_material_type', :facetable) + fields << Solrizer.solr_name('complex_material_sub_type', :facetable) + fields + end + + def self.material_type_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_material_type', :stored_searchable) + fields << Solrizer.solr_name('complex_material_sub_type', :stored_searchable) + fields << Solrizer.solr_name('complex_material_type_description', :stored_searchable) + fields << Solrizer.solr_name('complex_material_type_identifier', :symbol) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/organization_indexer.rb b/hyrax/app/indexers/complex_field/organization_indexer.rb new file mode 100644 index 00000000..aa247c39 --- /dev/null +++ b/hyrax/app/indexers/complex_field/organization_indexer.rb @@ -0,0 +1,41 @@ +module ComplexField + module OrganizationIndexer + def generate_solr_document + super.tap do |solr_doc| + index_organization(solr_doc) + end + end + + def index_organization(solr_doc) + solr_doc[Solrizer.solr_name('complex_organization', :displayable)] = object.complex_organization.to_json + solr_doc[Solrizer.solr_name('complex_organization', :stored_searchable)] = object.complex_organization.map { |o| o.organization.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_organization', :facetable)] = object.complex_organization.map { |o| o.organization.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_sub_organization', :stored_searchable)] = object.complex_organization.map { |o| o.sub_organization.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_sub_organization', :facetable)] = object.complex_organization.map { |o| o.sub_organization.reject(&:blank?).first } + end + + def self.organization_facet_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('complex_organization', :facetable) + fields << Solrizer.solr_name('complex_sub_organization', :facetable) + fields + end + + def self.organization_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_organization', :stored_searchable) + fields << Solrizer.solr_name('complex_sub_organization', :stored_searchable) + fields + end + + def self.organization_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_organization', :displayable) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/person_indexer.rb b/hyrax/app/indexers/complex_field/person_indexer.rb new file mode 100644 index 00000000..8d40ce3c --- /dev/null +++ b/hyrax/app/indexers/complex_field/person_indexer.rb @@ -0,0 +1,99 @@ +module ComplexField + module PersonIndexer + def generate_solr_document + super.tap do |solr_doc| + index_person(solr_doc) + end + end + + def index_person(solr_doc) + creators = object.complex_person.map { |c| (c.first_name + c.last_name).reject(&:blank?).join(' ') } + creators << object.complex_person.map { |c| c.name.reject(&:blank?) } + creators = creators.flatten.uniq.reject(&:blank?) + solr_doc[Solrizer.solr_name('complex_person', :stored_searchable)] = creators + solr_doc[Solrizer.solr_name('complex_person', :facetable)] = creators + solr_doc[Solrizer.solr_name('complex_person', :displayable)] = object.complex_person.to_json + object.complex_person.each do |c| + # index creator by role + person_name = c.name.reject(&:blank?) + person_name = (c.first_name + c.last_name).reject(&:blank?).join(' ') if person_name.blank? + label = 'other' + label = c.role.first unless c.role.blank? + label = label.downcase.tr(' ', '_') + # label has japanese and english text, so not using as name for solr field + # label = RoleService.new.label(c.role.first) + # complex_person by role as stored_searchable + fld_name = Solrizer.solr_name("complex_person_#{label}", :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << person_name + solr_doc[fld_name].flatten! + # complex_person by role as facetable + fld_name = Solrizer.solr_name("complex_person_#{label}", :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << person_name + solr_doc[fld_name].flatten! + # identifier + fld_name = Solrizer.solr_name('complex_person_identifier', :symbol) + vals = c.complex_identifier.map { |i| i.identifier.reject(&:blank?) } + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + # Affiliation + c.complex_affiliation.each do |ca| + ca.complex_organization.each do |co| + vals = co.organization.reject(&:blank?) + fld_name = Solrizer.solr_name('complex_person_organization', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + fld_name = Solrizer.solr_name('complex_person_organization', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + vals = co.sub_organization.reject(&:blank?) + fld_name = Solrizer.solr_name('complex_person_sub_organization', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + fld_name = Solrizer.solr_name('complex_person_sub_organization', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name] = solr_doc[fld_name].flatten.uniq + end + end + end + end + + def self.person_facet_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('complex_person_other', :facetable) + fields << Solrizer.solr_name('complex_person_author', :facetable) + fields << Solrizer.solr_name('complex_person_editor', :facetable) + fields << Solrizer.solr_name('complex_person_translator', :facetable) + fields << Solrizer.solr_name('complex_person_data_depositor', :facetable) + fields << Solrizer.solr_name('complex_person_data_curator', :facetable) + fields << Solrizer.solr_name('complex_person_contact_person', :facetable) + fields << Solrizer.solr_name('complex_person_operator', :facetable) + fields << Solrizer.solr_name('complex_person_organization', :facetable) + fields << Solrizer.solr_name('complex_person_sub_organization', :facetable) + fields + end + + def self.person_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_person', :stored_searchable) + fields << Solrizer.solr_name('complex_person_organization', :stored_searchable) + fields << Solrizer.solr_name('complex_person_sub_organization', :stored_searchable) + fields + end + + def self.person_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_person', :displayable) + fields + end + end +end diff --git a/hyrax/app/indexers/complex_field/purchase_record_indexer.rb b/hyrax/app/indexers/complex_field/purchase_record_indexer.rb new file mode 100644 index 00000000..3b28c0f5 --- /dev/null +++ b/hyrax/app/indexers/complex_field/purchase_record_indexer.rb @@ -0,0 +1,115 @@ +module ComplexField + module PurchaseRecordIndexer + def generate_solr_document + super.tap do |solr_doc| + index_purchase_record(solr_doc) + end + end + + def index_purchase_record(solr_doc) + object.complex_specimen_type.each do |st| + # purchase_record_item + fld_name = Solrizer.solr_name('complex_purchase_record_item', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + vals = st.complex_purchase_record.map { |i| i.purchase_record_item.reject(&:blank?) } + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # title + fld_name = Solrizer.solr_name('complex_purchase_record_title', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + vals = st.complex_purchase_record.map { |i| i.title.reject(&:blank?) } + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('complex_purchase_record_title', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + vals = st.complex_purchase_record.map { |i| i.title.reject(&:blank?) } + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + st.complex_purchase_record.each do |i| + # date + dates = i.date.reject(&:blank?) + unless dates.blank? + # date - datebale + fld_name = Solrizer.solr_name('complex_date_purchased', :dateable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + vals = dates.map { |dt| DateTime.parse(dt).utc.iso8601 } + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # date - displayable + fld_name = Solrizer.solr_name('complex_date_purchased', :displayable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << dates + solr_doc[fld_name].flatten! + end + # identifier + i.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('complex_purchase_record_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + # manufacturer + i.manufacturer.each do |org| + fld_name = Solrizer.solr_name('complex_purchase_record_manufacturer', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('complex_purchase_record_manufacturer', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('complex_purchase_record_manufacturer_sub_organization', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.sub_organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('complex_purchase_record_manufacturer_sub_organization', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.sub_organization.reject(&:blank?) + solr_doc[fld_name].flatten! + end + # supplier + i.supplier.each do |org| + fld_name = Solrizer.solr_name('complex_purchase_record_supplier', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('complex_purchase_record_supplier', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('complex_purchase_record_supplier_sub_organization', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.sub_organization.reject(&:blank?) + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name('complex_purchase_record_supplier_sub_organization', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << org.sub_organization.reject(&:blank?) + solr_doc[fld_name].flatten! + end + end + end + end + + def self.purchase_record_facet_fields + # solr fields that will be treated as facets + fields = [] + # fields << Solrizer.solr_name('complex_purchase_record_title', :facetable) + fields << Solrizer.solr_name('complex_purchase_record_manufacturer', :facetable) + fields << Solrizer.solr_name('complex_purchase_record_manufacturer_sub_organization', :facetable) + fields << Solrizer.solr_name('complex_purchase_record_supplier', :facetable) + fields << Solrizer.solr_name('complex_purchase_record_supplier_sub_organization', :facetable) + fields + end + + def self.purchase_record_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_purchase_record_title', :stored_searchable) + fields << Solrizer.solr_name('complex_purchase_record_item', :stored_searchable) + fields << Solrizer.solr_name('complex_purchase_record_manufacturer', :stored_searchable) + fields << Solrizer.solr_name('complex_purchase_record_manufacturer_sub_organization', :stored_searchable) + fields << Solrizer.solr_name('complex_purchase_record_supplier', :stored_searchable) + fields << Solrizer.solr_name('complex_purchase_record_supplier_sub_organization', :stored_searchable) + fields + end + end +end diff --git a/hyrax/app/indexers/complex_field/relation_indexer.rb b/hyrax/app/indexers/complex_field/relation_indexer.rb new file mode 100644 index 00000000..81d9ace0 --- /dev/null +++ b/hyrax/app/indexers/complex_field/relation_indexer.rb @@ -0,0 +1,33 @@ +module ComplexField + module RelationIndexer + def generate_solr_document + super.tap do |solr_doc| + index_relation(solr_doc) + end + end + + def index_relation(solr_doc) + solr_doc[Solrizer.solr_name('complex_relation', :displayable)] = object.complex_relation.to_json + solr_doc[Solrizer.solr_name('complex_relation_title', :stored_searchable)] = object.complex_relation.map { |r| r.title.reject(&:blank?).first } + object.complex_relation.each do |r| + unless r.title.blank? || r.relationship.blank? + fld_name = Solrizer.solr_name('complex_relation_relationship', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << r.relationship.reject(&:blank?) + solr_doc[fld_name].flatten! + + relationship = r.relationship.reject(&:blank?).first.downcase.tr(' ', '_') + fld_name = Solrizer.solr_name("complex_relation_#{relationship}", :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << r.title.reject(&:blank?) + solr_doc[fld_name].flatten! + + fld_name = Solrizer.solr_name("complex_relation_#{relationship}", :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << r.title.reject(&:blank?) + solr_doc[fld_name].flatten! + end + end + end + end +end diff --git a/hyrax/app/indexers/complex_field/rights_indexer.rb b/hyrax/app/indexers/complex_field/rights_indexer.rb new file mode 100644 index 00000000..3a69df5f --- /dev/null +++ b/hyrax/app/indexers/complex_field/rights_indexer.rb @@ -0,0 +1,36 @@ +module ComplexField + module RightsIndexer + def generate_solr_document + super.tap do |solr_doc| + index_rights(solr_doc) + end + end + + def index_rights(solr_doc) + solr_doc[Solrizer.solr_name('complex_rights', :displayable)] = object.complex_rights.to_json + solr_doc[Solrizer.solr_name('complex_rights', :facetable)] = object.complex_rights.map { |r| r.rights.reject(&:blank?).first } + end + + def self.rights_facet_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('complex_rights', :facetable) + fields + end + + def self.rights_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_rights', :facetable) + fields + end + + def self.rights_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_rights', :displayable) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/shape_indexer.rb b/hyrax/app/indexers/complex_field/shape_indexer.rb new file mode 100644 index 00000000..f074cf3e --- /dev/null +++ b/hyrax/app/indexers/complex_field/shape_indexer.rb @@ -0,0 +1,36 @@ +module ComplexField + module ShapeIndexer + def generate_solr_document + super.tap do |solr_doc| + index_shape(solr_doc) + end + end + + def index_shape(solr_doc) + object.complex_specimen_type.each do |st| + # description as complex_shape searchable + vals = st.complex_shape.map { |c| c.description.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_shape', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + st.complex_shape.each do |cc| + cc.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('complex_shape_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + end + end + end + + def self.shape_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_shape', :stored_searchable) + fields << Solrizer.solr_name('complex_shape_identifier', :symbol) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/source_indexer.rb b/hyrax/app/indexers/complex_field/source_indexer.rb new file mode 100644 index 00000000..1c5a7956 --- /dev/null +++ b/hyrax/app/indexers/complex_field/source_indexer.rb @@ -0,0 +1,57 @@ +module ComplexField + module SourceIndexer + def generate_solr_document + super.tap do |solr_doc| + index_source(solr_doc) + end + end + + def index_source(solr_doc) + solr_doc[Solrizer.solr_name('complex_source', :displayable)] = object.complex_source.to_json + solr_doc[Solrizer.solr_name('complex_source_title', :stored_searchable)] = object.complex_source.map { |i| i.title.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_source_title', :facetable)] = object.complex_source.map { |i| i.title.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_source_issue', :stored_searchable)] = object.complex_source.map { |i| i.issue.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_source_sequence_number', :stored_searchable)] = object.complex_source.map { |i| i.sequence_number.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_source_volume', :stored_searchable)] = object.complex_source.map { |i| i.volume.reject(&:blank?).first } + object.complex_source.each do |i| + i.complex_person.each do |pn| + person_name = pn.name.reject(&:blank?) + person_name = (pn.first_name + pn.last_name).reject(&:blank?).join(' ') if person_name.blank? + unless pn.role.blank? + label = pn.role.first + fld_name = Solrizer.solr_name("complex_person_#{label.downcase.tr(' ', '_')}", :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << person_name + solr_doc[fld_name].flatten! + fld_name = Solrizer.solr_name("complex_person_#{label.downcase.tr(' ', '_')}", :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << person_name + solr_doc[fld_name].flatten! + end + end + end + end + + def self.source_facet_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('complex_source_title', :facetable) + fields + end + + def self.source_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_source_title', :stored_searchable) + fields + end + + def self.source_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_source', :displayable) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/specimen_type_indexer.rb b/hyrax/app/indexers/complex_field/specimen_type_indexer.rb new file mode 100644 index 00000000..cfc59c67 --- /dev/null +++ b/hyrax/app/indexers/complex_field/specimen_type_indexer.rb @@ -0,0 +1,38 @@ +module ComplexField + module SpecimenTypeIndexer + def generate_solr_document + super.tap do |solr_doc| + index_specimen_type(solr_doc) + end + end + + def index_specimen_type(solr_doc) + solr_doc[Solrizer.solr_name('complex_specimen_type', :displayable)] = object.complex_specimen_type.to_json + solr_doc[Solrizer.solr_name('complex_specimen_type', :stored_searchable)] = object.complex_specimen_type.map { |s| s.title.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_specimen_type_description', :stored_searchable)] = object.complex_specimen_type.map { |s| s.description.reject(&:blank?).first } + object.complex_specimen_type.each do |st| + st.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('complex_specimen_type_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + end + end + + def self.specimen_type_search_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('complex_specimen_type', :stored_searchable) + fields << Solrizer.solr_name('complex_specimen_type_description', :stored_searchable) + fields + end + + def self.specimen_type_show_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('complex_specimen_type', :displayable) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/state_of_matter_indexer.rb b/hyrax/app/indexers/complex_field/state_of_matter_indexer.rb new file mode 100644 index 00000000..a2a414f9 --- /dev/null +++ b/hyrax/app/indexers/complex_field/state_of_matter_indexer.rb @@ -0,0 +1,36 @@ +module ComplexField + module StateOfMatterIndexer + def generate_solr_document + super.tap do |solr_doc| + index_state_of_matter(solr_doc) + end + end + + def index_state_of_matter(solr_doc) + object.complex_specimen_type.each do |st| + # description as complex_state_of_matter searchable + fld_name = Solrizer.solr_name('complex_state_of_matter', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + vals = st.complex_state_of_matter.map { |c| c.description.reject(&:blank?) } + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + st.complex_state_of_matter.each do |cc| + cc.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('complex_state_of_matter_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + end + end + end + + def self.state_of_matter_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_state_of_matter', :stored_searchable) + fields << Solrizer.solr_name('complex_state_of_matter_identifier', :symbol) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/structural_feature_indexer.rb b/hyrax/app/indexers/complex_field/structural_feature_indexer.rb new file mode 100644 index 00000000..209046f6 --- /dev/null +++ b/hyrax/app/indexers/complex_field/structural_feature_indexer.rb @@ -0,0 +1,69 @@ +module ComplexField + module StructuralFeatureIndexer + def generate_solr_document + super.tap do |solr_doc| + index_structural_feature(solr_doc) + end + end + + def index_structural_feature(solr_doc) + object.complex_specimen_type.each do |st| + # category as complex_structural_feature_category searchable + vals = st.complex_structural_feature.map { |c| c.category.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_structural_feature_category', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # structural_feature as complex_structural_feature_category facetable + fld_name = Solrizer.solr_name('complex_structural_feature_category', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # description as complex_structural_feature_description searchable + vals = st.complex_structural_feature.map { |c| c.description.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_structural_feature_description', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # sub_category as complex_structural_feature_sub_category searchable + vals = st.complex_structural_feature.map { |c| c.sub_category.reject(&:blank?) } + fld_name = Solrizer.solr_name('complex_structural_feature_sub_category', :stored_searchable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # sub_category as complex_structural_feature_category facetable + fld_name = Solrizer.solr_name('complex_structural_feature_sub_category', :facetable) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << vals + solr_doc[fld_name].flatten! + # identifier + st.complex_structural_feature.each do |cc| + cc.complex_identifier.each do |id| + fld_name = Solrizer.solr_name('complex_structural_feature_identifier', :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << id.identifier.reject(&:blank?).first + end + end + end + end + + def self.structural_feature_facet_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_structural_feature_category', :facetable) + fields << Solrizer.solr_name('complex_structural_feature_sub_category', :facetable) + fields + end + + def self.structural_feature_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_structural_feature_category', :stored_searchable) + fields << Solrizer.solr_name('complex_structural_feature_sub_category', :stored_searchable) + fields << Solrizer.solr_name('complex_structural_feature_description', :stored_searchable) + fields << Solrizer.solr_name('complex_structural_feature_identifier', :symbol) + fields + end + + end +end diff --git a/hyrax/app/indexers/complex_field/version_indexer.rb b/hyrax/app/indexers/complex_field/version_indexer.rb new file mode 100644 index 00000000..69a1cda1 --- /dev/null +++ b/hyrax/app/indexers/complex_field/version_indexer.rb @@ -0,0 +1,14 @@ +module ComplexField + module VersionIndexer + def generate_solr_document + super.tap do |solr_doc| + index_version(solr_doc) + end + end + + def index_version(solr_doc) + solr_doc[Solrizer.solr_name('complex_version', :symbol)] = object.complex_version.map { |v| v.version.reject(&:blank?).first } + solr_doc[Solrizer.solr_name('complex_version', :displayable)] = object.complex_version.to_json + end + end +end diff --git a/hyrax/app/indexers/dataset_indexer.rb b/hyrax/app/indexers/dataset_indexer.rb new file mode 100644 index 00000000..f74fb02a --- /dev/null +++ b/hyrax/app/indexers/dataset_indexer.rb @@ -0,0 +1,108 @@ +# Generated via +# `rails generate hyrax:work Dataset` +class DatasetIndexer < NgdrIndexer + # Custom indexers for dataset model + include ComplexField::DateIndexer + include ComplexField::IdentifierIndexer + include ComplexField::CustomPropertyIndexer + include ComplexField::PersonIndexer + include ComplexField::RightsIndexer + include ComplexField::VersionIndexer + include ComplexField::OrganizationIndexer + include ComplexField::InstrumentIndexer + include ComplexField::RelationIndexer + include ComplexField::SpecimenTypeIndexer + include ComplexField::ChemicalCompositionIndexer + include ComplexField::CrystallographicStructureIndexer + include ComplexField::MaterialTypeIndexer + include ComplexField::PurchaseRecordIndexer + include ComplexField::ShapeIndexer + include ComplexField::StateOfMatterIndexer + include ComplexField::StructuralFeatureIndexer + + def self.facet_fields + # solr fields that will be treated as facets + super.tap do |fields| + dataset_facet_fields = [ + 'computational_methods', + 'data_origin', + 'properties_addressed', + 'synthesis_and_processing', + 'characterization_methods' + ] + dataset_facet_fields.each do |fld| + fields << Solrizer.solr_name(fld, :facetable) + end + fields.concat ComplexField::DateIndexer.date_facet_fields + fields.concat ComplexField::PersonIndexer.person_facet_fields + fields.concat ComplexField::OrganizationIndexer.organization_facet_fields + fields.concat ComplexField::RightsIndexer.rights_facet_fields + fields.concat ComplexField::InstrumentIndexer.instrument_facet_fields + fields.concat ComplexField::MaterialTypeIndexer.material_type_facet_fields + fields.concat ComplexField::PurchaseRecordIndexer.purchase_record_facet_fields + fields.concat ComplexField::StateOfMatterIndexer.state_of_matter_search_fields + fields.concat ComplexField::StructuralFeatureIndexer.structural_feature_facet_fields + end + end + + def self.search_fields + # solr fields that will be used for a search + super.tap do |fields| + dataset_search_fields = [ + 'alternative_title', + 'characterization_methods', + 'computational_methods', + 'data_origin', + 'origin_system_provenance', + 'properties_addressed', + 'specimen_set', + 'synthesis_and_processing', + ] + dataset_search_fields.each do |fld| + fields << Solrizer.solr_name(fld, :stored_searchable) + end + fields.concat ComplexField::IdentifierIndexer.identifier_search_fields + fields.concat ComplexField::DateIndexer.date_search_fields + fields.concat ComplexField::CustomPropertyIndexer.custom_property_search_fields + fields.concat ComplexField::PersonIndexer.person_search_fields + fields.concat ComplexField::RightsIndexer.rights_search_fields + fields.concat ComplexField::OrganizationIndexer.organization_search_fields + fields.concat ComplexField::InstrumentIndexer.instrument_search_fields + fields.concat ComplexField::SpecimenTypeIndexer.specimen_type_search_fields + fields.concat ComplexField::ChemicalCompositionIndexer.chemical_composition_search_fields + fields.concat ComplexField::CrystallographicStructureIndexer.crystallographic_structure_search_fields + fields.concat ComplexField::MaterialTypeIndexer.material_type_search_fields + fields.concat ComplexField::PurchaseRecordIndexer.purchase_record_search_fields + fields.concat ComplexField::ShapeIndexer.shape_search_fields + fields.concat ComplexField::StructuralFeatureIndexer.structural_feature_search_fields + end + end + + def self.show_fields + # solr fields that will be used to display results on the record page + super.tap do |fields| + dataset_show_fields = [ + 'alternative_title', + 'characterization_methods', + 'computational_methods', + 'data_origin', + 'origin_system_provenance', + 'properties_addressed', + 'specimen_set', + 'synthesis_and_processing', + ] + dataset_show_fields.each do |fld| + fields << Solrizer.solr_name(fld, :stored_searchable) + end + fields.concat ComplexField::IdentifierIndexer.identifier_show_fields + fields.concat ComplexField::DateIndexer.date_show_fields + fields.concat ComplexField::CustomPropertyIndexer.custom_property_show_fields + fields.concat ComplexField::PersonIndexer.person_show_fields + fields.concat ComplexField::RightsIndexer.rights_show_fields + fields.concat ComplexField::OrganizationIndexer.organization_show_fields + fields.concat ComplexField::InstrumentIndexer.instrument_show_fields + fields.concat ComplexField::SpecimenTypeIndexer.specimen_type_show_fields + end + end + +end diff --git a/hyrax/app/indexers/image_indexer.rb b/hyrax/app/indexers/image_indexer.rb new file mode 100644 index 00000000..211a2c27 --- /dev/null +++ b/hyrax/app/indexers/image_indexer.rb @@ -0,0 +1,46 @@ +# Generated via +# `rails generate hyrax:work Image` +class ImageIndexer < NgdrIndexer + # Custom indexers for image model + include ComplexField::DateIndexer + include ComplexField::IdentifierIndexer + include ComplexField::PersonIndexer + include ComplexField::RightsIndexer + include ComplexField::VersionIndexer + include ComplexField::CustomPropertyIndexer + include ComplexField::RelationIndexer + + def self.facet_fields + super.tap do |fields| + fields << Solrizer.solr_name('instrument', :facetable) + fields << Solrizer.solr_name('specimen_set', :facetable) + fields.concat ComplexField::DateIndexer.date_facet_fields + fields.concat ComplexField::PersonIndexer.person_facet_fields + fields.concat ComplexField::RightsIndexer.rights_facet_fields + end + end + + def self.search_fields + super.tap do |fields| + fields << Solrizer.solr_name('instrument', :stored_searchable) + fields << Solrizer.solr_name('specimen_set', :stored_searchable) + fields.concat ComplexField::DateIndexer.date_search_fields + fields.concat ComplexField::IdentifierIndexer.identifier_search_fields + fields.concat ComplexField::PersonIndexer.person_search_fields + fields.concat ComplexField::RightsIndexer.rights_search_fields + fields.concat ComplexField::CustomPropertyIndexer.custom_property_search_fields + end + end + + def self.show_fields + super.tap do |fields| + fields << Solrizer.solr_name('instrument', :stored_searchable) + fields << Solrizer.solr_name('specimen_set', :stored_searchable) + fields.concat ComplexField::DateIndexer.date_show_fields + fields.concat ComplexField::IdentifierIndexer.identifier_show_fields + fields.concat ComplexField::PersonIndexer.person_show_fields + fields.concat ComplexField::RightsIndexer.rights_show_fields + fields.concat ComplexField::CustomPropertyIndexer.custom_property_show_fields + end + end +end diff --git a/hyrax/app/indexers/ngdr_indexer.rb b/hyrax/app/indexers/ngdr_indexer.rb new file mode 100644 index 00000000..872fe2d5 --- /dev/null +++ b/hyrax/app/indexers/ngdr_indexer.rb @@ -0,0 +1,80 @@ +class NgdrIndexer < Hyrax::WorkIndexer + # This indexes the default metadata. You can remove it if you want to + # provide your own metadata and indexing. + include Hyrax::IndexesBasicMetadata + + # Fetch remote labels for based_near. You can remove this if you don't want + # this behavior + include Hyrax::IndexesLinkedMetadata + + def self.facet_fields + # solr fields that will be treated as facets + [ + # core and basic metadata fields - not interested in these + # Solrizer.solr_name('creator', :facetable), + # Solrizer.solr_name('contributor', :facetable), + # Solrizer.solr_name('based_near_label', :facetable), + + # system fields + Solrizer.solr_name('file_format', :facetable), + Solrizer.solr_name('human_readable_type', :facetable), + Solrizer.solr_name('member_of_collections', :symbol), + + # core and basic metadata fields + Solrizer.solr_name('keyword', :facetable), + Solrizer.solr_name('language', :facetable), + Solrizer.solr_name('publisher', :facetable), + Solrizer.solr_name('resource_type', :facetable), + Solrizer.solr_name('subject', :facetable), + ] + end + + def self.search_fields + # solr fields that will be used for a search + [ + Solrizer.solr_name('title', :stored_searchable), + Solrizer.solr_name('description', :stored_searchable), + Solrizer.solr_name('keyword', :stored_searchable), + Solrizer.solr_name('subject', :stored_searchable), + Solrizer.solr_name('publisher', :stored_searchable), + Solrizer.solr_name('language', :stored_searchable), + Solrizer.solr_name('date_uploaded', :stored_searchable), + Solrizer.solr_name('date_modified', :stored_searchable), + Solrizer.solr_name('date_created', :stored_searchable), + Solrizer.solr_name('rights_statement', :stored_searchable), + Solrizer.solr_name('license', :stored_searchable), + Solrizer.solr_name('resource_type', :stored_searchable), + Solrizer.solr_name('format', :stored_searchable), + Solrizer.solr_name('identifier', :stored_searchable), + Solrizer.solr_name('place', :stored_searchable), + Solrizer.solr_name('status', :stored_searchable), + Solrizer.solr_name('issue', :stored_searchable) + ] + end + + def self.show_fields + # solr fields that will be used to display results on the record page + [ + # Solrizer.solr_name('creator', :stored_searchable), + # Solrizer.solr_name('contributor', :stored_searchable), + # Solrizer.solr_name('based_near_label', :stored_searchable), + Solrizer.solr_name('title', :stored_searchable), + Solrizer.solr_name('description', :stored_searchable), + Solrizer.solr_name('keyword', :stored_searchable), + Solrizer.solr_name('subject', :stored_searchable), + Solrizer.solr_name('publisher', :stored_searchable), + Solrizer.solr_name('language', :stored_searchable), + Solrizer.solr_name('date_uploaded', :stored_searchable), + Solrizer.solr_name('date_modified', :stored_searchable), + Solrizer.solr_name('date_created', :stored_searchable), + Solrizer.solr_name('rights_statement', :stored_searchable), + Solrizer.solr_name('license', :stored_searchable), + Solrizer.solr_name('resource_type', :stored_searchable), + Solrizer.solr_name('format', :stored_searchable), + Solrizer.solr_name('identifier', :stored_searchable), + Solrizer.solr_name('place', :stored_searchable), + Solrizer.solr_name('status', :stored_searchable), + Solrizer.solr_name('issue', :stored_searchable) + ] + end +end diff --git a/hyrax/app/indexers/publication_indexer.rb b/hyrax/app/indexers/publication_indexer.rb new file mode 100644 index 00000000..04eeddd7 --- /dev/null +++ b/hyrax/app/indexers/publication_indexer.rb @@ -0,0 +1,52 @@ +# Generated via +# `rails generate hyrax:work Publication` +class PublicationIndexer < NgdrIndexer + # Custom indexers for publication model + include ComplexField::DateIndexer + include ComplexField::IdentifierIndexer + include ComplexField::PersonIndexer + include ComplexField::RightsIndexer + include ComplexField::VersionIndexer + include ComplexField::EventIndexer + include ComplexField::SourceIndexer + + def self.facet_fields + super.tap do |fields| + fields << Solrizer.solr_name('place', :facetable) + fields.concat ComplexField::DateIndexer.date_facet_fields + fields.concat ComplexField::PersonIndexer.person_facet_fields + fields.concat ComplexField::RightsIndexer.rights_facet_fields + fields.concat ComplexField::EventIndexer.event_facet_fields + fields.concat ComplexField::SourceIndexer.source_facet_fields + end + end + + def self.search_fields + super.tap do |fields| + fields << Solrizer.solr_name('issue', :stored_searchable) + fields << Solrizer.solr_name('place', :stored_searchable) + fields << Solrizer.solr_name('table_of_contents', :stored_searchable) + fields.concat ComplexField::DateIndexer.date_search_fields + fields.concat ComplexField::IdentifierIndexer.identifier_search_fields + fields.concat ComplexField::PersonIndexer.person_search_fields + fields.concat ComplexField::RightsIndexer.rights_search_fields + fields.concat ComplexField::EventIndexer.event_search_fields + fields.concat ComplexField::SourceIndexer.source_search_fields + end + end + + def self.show_fields + super.tap do |fields| + fields << Solrizer.solr_name('issue', :stored_searchable) + fields << Solrizer.solr_name('place', :stored_searchable) + fields << Solrizer.solr_name('table_of_contents', :stored_searchable) + fields.concat ComplexField::DateIndexer.date_show_fields + fields.concat ComplexField::IdentifierIndexer.identifier_show_fields + fields.concat ComplexField::PersonIndexer.person_show_fields + fields.concat ComplexField::RightsIndexer.rights_show_fields + fields.concat ComplexField::EventIndexer.event_show_fields + fields.concat ComplexField::SourceIndexer.source_show_fields + end + end + +end diff --git a/hyrax/app/indexers/work_indexer.rb b/hyrax/app/indexers/work_indexer.rb index 156b627d..92134ef8 100644 --- a/hyrax/app/indexers/work_indexer.rb +++ b/hyrax/app/indexers/work_indexer.rb @@ -1,18 +1,5 @@ # Generated via # `rails generate hyrax:work Work` -class WorkIndexer < Hyrax::WorkIndexer - # This indexes the default metadata. You can remove it if you want to - # provide your own metadata and indexing. - include Hyrax::IndexesBasicMetadata - - # Fetch remote labels for based_near. You can remove this if you don't want - # this behavior - include Hyrax::IndexesLinkedMetadata - - # Uncomment this block if you want to add custom indexing behavior: - # def generate_solr_document - # super.tap do |solr_doc| - # solr_doc['my_custom_field_ssim'] = object.my_custom_property - # end - # end +class WorkIndexer < NgdrIndexer + # Add custom indexers for work model end diff --git a/hyrax/app/inputs/nested_affiliation_input.rb b/hyrax/app/inputs/nested_affiliation_input.rb new file mode 100644 index 00000000..1c28cb60 --- /dev/null +++ b/hyrax/app/inputs/nested_affiliation_input.rb @@ -0,0 +1,69 @@ +class NestedAffiliationInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- job_title + out << "
" + field = :job_title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
' + + out << "
" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
' + out << '
' + + # --- complex_organization + field = :complex_organization + field_value = value.send(field) + if field_value.blank? + value.complex_organization.build + field_value = value.send(field) + end + nested_fields = NestedOrganizationInput.new(@builder, field, nil, :multi_value, {}) + out << "
" + out << "
" + # out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
" + # out << " " + out << "
" # row + + # last row + # --- delete checkbox + if repeats == true + out << "
" + field_label = 'Affiliation' + out << "
" + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
' + out << '
' # last row + end + + out + end +end diff --git a/hyrax/app/inputs/nested_attributes_input.rb b/hyrax/app/inputs/nested_attributes_input.rb new file mode 100644 index 00000000..edc07cde --- /dev/null +++ b/hyrax/app/inputs/nested_attributes_input.rb @@ -0,0 +1,119 @@ +class NestedAttributesInput < MultiValueInput + + def input(wrapper_options) + super + end + + def nested_input(wrapper_options, values, parent=@builder.object_name) + @rendered_first_element = false + input_html_classes.unshift('string') + input_html_options[:name] ||= "#{parent}[#{attribute_name}][]" + input_html_options[:repeats] = false + nested_outer_wrapper do + buffer_each(values) do |value, index| + nested_inner_wrapper do + build_field(value, index, parent) + end + end + end + end + + protected + + def nested_outer_wrapper + " \n" + end + + def nested_inner_wrapper + <<-HTML +
  • + #{yield} +
  • + HTML + end + + def build_field(value, index, parent=@builder.object_name) + options = input_html_options.dup + if !value.kind_of? ActiveTriples::Resource + association = @builder.object.model.send(attribute_name) + value = association.build + end + # if value.kind_of? ActiveTriples::Resource + options[:name] = name_for(attribute_name, index, 'hidden_label'.freeze, parent) + options[:id] = id_for(attribute_name, index, 'hidden_label'.freeze, parent) + + if value.new_record? + build_options_for_new_row(attribute_name, index, options) + else + build_options_for_existing_row(attribute_name, index, value, options) + end + # end + + options[:required] = nil if @rendered_first_element + + options[:class] ||= [] + options[:class] += ["#{input_dom_id} form-control multi-text-field"] + options[:'aria-labelledby'] = label_id + + @rendered_first_element = true + + out = '' + out << build_components(attribute_name, value, index, options, parent) + out << hidden_id_field(value, index, parent) unless value.new_record? + out + end + + def destroy_widget(attribute_name, index, field_label="field", parent=@builder.object_name) + out = '' + out << hidden_destroy_field(attribute_name, index, parent) + out << " " + out + end + + def hidden_id_field(value, index, parent=@builder.object_name) + name = id_name_for(attribute_name, index, parent) + id = id_for(attribute_name, index, 'id'.freeze, parent) + hidden_value = value.new_record? ? '' : value.rdf_subject + @builder.hidden_field(attribute_name, name: name, id: id, value: hidden_value, data: { id: 'remote' }) + end + + def hidden_destroy_field(attribute_name, index, parent=@builder.object_name) + name = destroy_name_for(attribute_name, index, parent) + id = id_for(attribute_name, index, '_destroy'.freeze, parent) + hidden_value = false + @builder.hidden_field(attribute_name, name: name, id: id, + value: hidden_value, data: { destroy: true }, class: 'form-control remove-hidden') + end + + def build_options_for_new_row(_attribute_name, _index, options) + options[:value] = '' + end + + def build_options_for_existing_row(_attribute_name, _index, value, options) + options[:value] = value.rdf_label.first || "Unable to fetch label for #{value.rdf_subject}" + end + + def name_for(attribute_name, index, field, parent=@builder.object_name) + "#{parent}[#{attribute_name}_attributes][#{index}][#{field}][]" + end + + def id_name_for(attribute_name, index, parent=@builder.object_name) + singular_input_name_for(attribute_name, index, 'id', parent) + end + + def destroy_name_for(attribute_name, index, parent=@builder.object_name) + singular_input_name_for(attribute_name, index, '_destroy', parent) + end + + def singular_input_name_for(attribute_name, index, field, parent=@builder.object_name) + "#{parent}[#{attribute_name}_attributes][#{index}][#{field}]" + end + + def id_for(attribute_name, index, field, parent=@builder.object_name) + [parent, "#{attribute_name}_attributes", index, field].join('_'.freeze) + end +end diff --git a/hyrax/app/inputs/nested_chemical_composition_input.rb b/hyrax/app/inputs/nested_chemical_composition_input.rb new file mode 100644 index 00000000..4f6f3379 --- /dev/null +++ b/hyrax/app/inputs/nested_chemical_composition_input.rb @@ -0,0 +1,68 @@ +class NestedChemicalCompositionInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # last row + out << "
    " + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + + # --- delete checkbox + if repeats == true + field_label = 'Chemical composition' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_crystallographic_structure_input.rb b/hyrax/app/inputs/nested_crystallographic_structure_input.rb new file mode 100644 index 00000000..ed525205 --- /dev/null +++ b/hyrax/app/inputs/nested_crystallographic_structure_input.rb @@ -0,0 +1,68 @@ +class NestedCrystallographicStructureInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # last row + out << "
    " + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + + # --- delete checkbox + if repeats == true + field_label = 'Crystallographic structure' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_custom_property_input.rb b/hyrax/app/inputs/nested_custom_property_input.rb new file mode 100644 index 00000000..040f66de --- /dev/null +++ b/hyrax/app/inputs/nested_custom_property_input.rb @@ -0,0 +1,64 @@ +class NestedCustomPropertyInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:custom_property) and index == 0 + required = true + end + + # Add remove elemnt only if element repeats + repeats = options.delete(:repeats) + repeats = true if repeats.nil? + + # --- label + field = :label + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # last row + out << "
    " + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id)) + out << '
    ' + + # --- delete checkbox + if repeats == true + field_label = 'Additional metadata' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_date_input.rb b/hyrax/app/inputs/nested_date_input.rb new file mode 100644 index 00000000..cfe3aeda --- /dev/null +++ b/hyrax/app/inputs/nested_date_input.rb @@ -0,0 +1,55 @@ +class NestedDateInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_date) and index == 0 + required = true + end + + # Add remove elemnt only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + # --- description and date - single row + out << "
    " + + # description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + date_options = DateService.new.select_all_options + out << "
    " + out << template.select_tag(field_name, template.options_for_select(date_options, field_value), + label: '', class: 'select form-control', prompt: 'choose type', id: field_id) + out << '
    ' + + # --- date + field = :date + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, + data: { provide: 'datepicker' }, required: required)) + out << '
    ' + + # --- delete checkbox + if repeats == true + field_label = 'Date' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_event_input.rb b/hyrax/app/inputs/nested_event_input.rb new file mode 100644 index 00000000..a94505ab --- /dev/null +++ b/hyrax/app/inputs/nested_event_input.rb @@ -0,0 +1,111 @@ +class NestedEventInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_event) and index == 0 + required = true + end + + # --- title + field = :title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- place + field = :place + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + out << '
    ' # row + + # --- start_date + field = :start_date + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, + data: { provide: 'datepicker' }, required: false)) + out << '
    ' + out << '
    ' # row + + # --- end_date + field = :end_date + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, + data: { provide: 'datepicker' }, required: false)) + out << '
    ' + out << '
    ' # row + + # last row + out << "
    " + + # --- invitation_status + field = :invitation_status + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + + # --- delete checkbox + field_label = 'Event' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_identifier_input.rb b/hyrax/app/inputs/nested_identifier_input.rb new file mode 100644 index 00000000..4e4323ec --- /dev/null +++ b/hyrax/app/inputs/nested_identifier_input.rb @@ -0,0 +1,57 @@ +class NestedIdentifierInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_identifier) and index == 0 + required = true + end + + # Add remove elemnt only if element repeats + repeats = options.delete(:repeats) + repeats = true if repeats.nil? + + # --- scheme and id - single row + out << "
    " + + # --- scheme + field = :scheme + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + id_options = IdentifierService.new.select_all_options + + out << "
    " + out << template.select_tag(field_name, + template.options_for_select(id_options, field_value), + label: '', class: 'select form-control', prompt: 'choose type', id: field_id) + out << '
    ' + + # --- identifier + field = :identifier + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, + required: required)) + out << '
    ' + + # --- delete checkbox + if repeats == true + field_label = 'Identifier' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_instrument_function_input.rb b/hyrax/app/inputs/nested_instrument_function_input.rb new file mode 100644 index 00000000..808b3ac5 --- /dev/null +++ b/hyrax/app/inputs/nested_instrument_function_input.rb @@ -0,0 +1,98 @@ +class NestedInstrumentFunctionInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + # --- column_number + field = :column_number + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- category + field = :category + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- sub_category + field = :sub_category + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # last row + out << "
    " + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + + # --- delete checkbox + if repeats == true + field_label = 'Instrument function' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_instrument_input.rb b/hyrax/app/inputs/nested_instrument_input.rb new file mode 100644 index 00000000..6ac26c63 --- /dev/null +++ b/hyrax/app/inputs/nested_instrument_input.rb @@ -0,0 +1,219 @@ +class NestedInstrumentInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- title + field = :title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- alternative_title + field = :alternative_title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- complex_date + field = :complex_date + field_value = value.send(field) + if field_value.blank? + value.complex_date.build + value.complex_date[0]['description'] = 'Processed' + field_value = value.send(field) + end + nested_fields = NestedDateInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- instrument_function + field = :instrument_function + field_value = value.send(field) + if field_value.blank? + value.instrument_function.build + field_value = value.send(field) + end + nested_fields = NestedInstrumentFunctionInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- manufacturer + field = :manufacturer + field_value = value.send(field) + if field_value.blank? + value.manufacturer.build + value.manufacturer[0].purpose = 'Manufacturer' + field_value = value.send(field) + end + nested_fields = NestedOrganizationInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- model_number + field = :model_number + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- complex_person + field = :complex_person + field_value = value.send(field) + if field_value.blank? + value.complex_person.build + value.complex_person[0].role = 'operator' + field_value = value.send(field) + end + nested_fields = NestedPersonInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- managing_organization + field = :managing_organization + field_value = value.send(field) + if field_value.blank? + value.managing_organization.build + value.managing_organization[0].purpose = 'Managing organization' + field_value = value.send(field) + end + nested_fields = NestedOrganizationInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # last row + # --- delete checkbox + if repeats == true + out << "
    " + field_label = 'Instrument' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + out << '
    ' # last row + end + + out + end +end diff --git a/hyrax/app/inputs/nested_material_type_input.rb b/hyrax/app/inputs/nested_material_type_input.rb new file mode 100644 index 00000000..252556ad --- /dev/null +++ b/hyrax/app/inputs/nested_material_type_input.rb @@ -0,0 +1,102 @@ +class NestedMaterialTypeInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats = options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- material_type + field = :material_type + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- material_sub_type + field = :material_sub_type + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- delete checkbox + if repeats == true + field_label = 'Material type' + out << "
    " + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + out << '
    ' # last row + end + + out + end +end diff --git a/hyrax/app/inputs/nested_organization_input.rb b/hyrax/app/inputs/nested_organization_input.rb new file mode 100644 index 00000000..487519d1 --- /dev/null +++ b/hyrax/app/inputs/nested_organization_input.rb @@ -0,0 +1,82 @@ +class NestedOrganizationInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_organization) and index == 0 + required = true + end + + # Add remove elemnt only if element repeats + repeats = options.delete(:repeats) + repeats = true if repeats.nil? + + # --- organization + field = :organization + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- sub_organization + field = :sub_organization + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + out << '
    ' # row + + # last row + out << "
    " + + # --- purpose + # NOTE: This is hidden and exists so we can enter the value on behalf of the user + field = :purpose + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << " ' + + out << " ' + + # --- delete checkbox + if repeats == true + field_label = 'Organization' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_person_input.rb b/hyrax/app/inputs/nested_person_input.rb new file mode 100644 index 00000000..f82784ea --- /dev/null +++ b/hyrax/app/inputs/nested_person_input.rb @@ -0,0 +1,106 @@ +class NestedPersonInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove elemnt only if element repeats + repeats = options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- name + field = :name + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- role + role_options = RoleService.new.select_all_options + field = :role + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << template.select_tag(field_name, template.options_for_select(role_options, field_value), + prompt: 'Select role played', label: '', class: 'select form-control', id: field_id, required: required) + out << '
    ' + out << '
    ' # row + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- complex_affiliation + field = :complex_affiliation + field_value = value.send(field) + if field_value.blank? + value.complex_affiliation.build + field_value = value.send(field) + end + nested_fields = NestedAffiliationInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # last row + # --- delete checkbox + if repeats == true + field_label = 'Person' + out << "
    " + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + out << '
    ' # last row + end + + out + end +end diff --git a/hyrax/app/inputs/nested_purchase_record_input.rb b/hyrax/app/inputs/nested_purchase_record_input.rb new file mode 100644 index 00000000..e3cee1f4 --- /dev/null +++ b/hyrax/app/inputs/nested_purchase_record_input.rb @@ -0,0 +1,144 @@ +class NestedPurchaseRecordInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- title + field = :title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- date + field = :date + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, + data: { provide: 'datepicker' }, required: required)) + out << '
    ' + out << '
    ' # row + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- supplier + field = :supplier + field_value = value.send(field) + if field_value.blank? + value.supplier.build + value.supplier[0].purpose = 'Supplier' + field_value = value.send(field) + end + nested_fields = NestedOrganizationInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- manufacturer + field = :manufacturer + field_value = value.send(field) + if field_value.blank? + value.manufacturer.build + value.manufacturer[0].purpose = 'Manufacturer' + field_value = value.send(field) + end + nested_fields = NestedOrganizationInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- purchase_record_item + field = :purchase_record_item + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # last row + # --- delete checkbox + if repeats == true + out << "
    " + field_label = 'Purchase record' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + out << '
    ' # last row + end + + out + end +end diff --git a/hyrax/app/inputs/nested_relation_input.rb b/hyrax/app/inputs/nested_relation_input.rb new file mode 100644 index 00000000..352ff8a9 --- /dev/null +++ b/hyrax/app/inputs/nested_relation_input.rb @@ -0,0 +1,95 @@ +class NestedRelationInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_relation) and index == 0 + required = true + end + + # --- title + field = :title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, 'Title', required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- url + field = :url + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # # --- identifier + # field = :identifier + # field_value = value.send(field).first + # field_id = id_for(attribute_name, index, field, parent) + # field_name = name_for(attribute_name, index, field, parent) + + # out << "
    " + # out << "
    " + # out << template.label_tag(field_name, field.to_s.humanize, required: false) + # out << '
    ' + + # out << "
    " + # out << @builder.text_field(field_name, + # options.merge(value: field_value, name: field_name, id: field_id, required: false)) + # out << '
    ' + # out << '
    ' # row + + # last row + out << "
    " + + # --- relationship + field = :relationship + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + role_options = RelationshipService.new.select_all_options + + out << "
    " + out << template.label_tag(field_name, 'Relationship', required: required) + out << '
    ' + + out << "
    " + out << template.select_tag(field_name, + template.options_for_select(role_options, field_value), + label: '', class: 'select form-control', prompt: 'choose relationship', + id: field_id, required: required) + out << '
    ' + + # --- delete checkbox + field_label ='Related work' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_rights_input.rb b/hyrax/app/inputs/nested_rights_input.rb new file mode 100644 index 00000000..7d7a9bec --- /dev/null +++ b/hyrax/app/inputs/nested_rights_input.rb @@ -0,0 +1,62 @@ +class NestedRightsInput < NestedAttributesInput + + protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_rights) and index == 0 + required = true + end + + # --- rights + field = :rights + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + active_options = Hyrax::LicenseService.new.select_active_options + + out << "
    " + out << "
    " + out << template.label_tag(field_name, 'Rights', required: required) + out << '
    ' + + out << "
    " + out << template.select_tag(field_name, + template.options_for_select(active_options, field_value), + prompt: 'Select license', label: '', class: 'select form-control', + id: field_id, required: required) + out << '
    ' + out << '
    ' # row + + # last row + out << "
    " + + # --- start date + field = :date + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, + data: { provide: 'datepicker' }, required: false)) + out << '
    ' + + # delete checkbox + field_label = 'Rights' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_shape_input.rb b/hyrax/app/inputs/nested_shape_input.rb new file mode 100644 index 00000000..11bf17c0 --- /dev/null +++ b/hyrax/app/inputs/nested_shape_input.rb @@ -0,0 +1,68 @@ +class NestedShapeInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # last row + out << "
    " + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + + # --- delete checkbox + if repeats == true + field_label = 'Shape' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_source_input.rb b/hyrax/app/inputs/nested_source_input.rb new file mode 100644 index 00000000..cb0b72fd --- /dev/null +++ b/hyrax/app/inputs/nested_source_input.rb @@ -0,0 +1,160 @@ +class NestedSourceInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_source) and index == 0 + required = true + end + + # --- title + field = :title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- alternative_title + field = :alternative_title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + out << '
    ' # row + + # --- start_page + field = :start_page + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + out << '
    ' # row + + # --- end_page + field = :end_page + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + out << '
    ' # row + + # --- issue + field = :issue + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + out << '
    ' # row + + # --- sequence_number + field = :sequence_number + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + out << '
    ' # row + + # --- total_number_of_pages + field = :total_number_of_pages + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + out << '
    ' # row + + # last row + out << "
    " + + # --- volume + field = :volume + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + + # --- delete checkbox + field_label = 'Source' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_specimen_type_input.rb b/hyrax/app/inputs/nested_specimen_type_input.rb new file mode 100644 index 00000000..70deb97d --- /dev/null +++ b/hyrax/app/inputs/nested_specimen_type_input.rb @@ -0,0 +1,219 @@ +class NestedSpecimenTypeInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- title + field = :title + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- complex_chemical_composition + field = :complex_chemical_composition + field_value = value.send(field) + if field_value.blank? + value.complex_chemical_composition.build + field_value = value.send(field) + end + nested_fields = NestedChemicalCompositionInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- complex_crystallographic_structure + field = :complex_crystallographic_structure + field_value = value.send(field) + if field_value.blank? + value.complex_crystallographic_structure.build + field_value = value.send(field) + end + nested_fields = NestedCrystallographicStructureInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- complex_material_type + field = :complex_material_type + field_value = value.send(field) + if field_value.blank? + value.complex_material_type.build + field_value = value.send(field) + end + nested_fields = NestedMaterialTypeInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- complex_purchase_record + field = :complex_purchase_record + field_value = value.send(field) + if field_value.blank? + value.complex_purchase_record.build + field_value = value.send(field) + end + nested_fields = NestedPurchaseRecordInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- complex_shape + field = :complex_shape + field_value = value.send(field) + if field_value.blank? + value.complex_shape.build + field_value = value.send(field) + end + nested_fields = NestedShapeInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- complex_state_of_matter + field = :complex_state_of_matter + field_value = value.send(field) + if field_value.blank? + value.complex_state_of_matter.build + field_value = value.send(field) + end + nested_fields = NestedStateOfMatterInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- complex_structural_feature + field = :complex_structural_feature + field_value = value.send(field) + if field_value.blank? + value.complex_structural_feature.build + field_value = value.send(field) + end + nested_fields = NestedStructuralFeatureInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # last row + # --- delete checkbox + if repeats == true + out << "
    " + field_label = 'Specimen type' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + out << '
    ' # row + end + + out + end +end diff --git a/hyrax/app/inputs/nested_state_of_matter_input.rb b/hyrax/app/inputs/nested_state_of_matter_input.rb new file mode 100644 index 00000000..bc4a6832 --- /dev/null +++ b/hyrax/app/inputs/nested_state_of_matter_input.rb @@ -0,0 +1,68 @@ +class NestedStateOfMatterInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats =options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # last row + out << "
    " + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: false)) + out << '
    ' + + # --- delete checkbox + if repeats == true + field_label = 'State of matter' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + end + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_structural_feature_input.rb b/hyrax/app/inputs/nested_structural_feature_input.rb new file mode 100644 index 00000000..895af921 --- /dev/null +++ b/hyrax/app/inputs/nested_structural_feature_input.rb @@ -0,0 +1,102 @@ +class NestedStructuralFeatureInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_person) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats = options.delete(:repeats) + repeats = true if repeats.nil? + + parent_attribute = name_for(attribute_name, index, '', parent)[0..-5] + + # --- category + field = :category + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- sub_category + field = :sub_category + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- description + field = :description + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- complex_identifier + field = :complex_identifier + field_value = value.send(field) + if field_value.blank? + value.complex_identifier.build + field_value = value.send(field) + end + nested_fields = NestedIdentifierInput.new(@builder, field, nil, :multi_value, {}) + out << "
    " + out << "
    " + out << " " + out << nested_fields.nested_input({:class=>"form-control", :repeats => false}, field_value, parent_attribute) + out << "
    " + # out << " " + out << "
    " # row + + # --- delete checkbox + if repeats == true + field_label = 'Structural feature' + out << "
    " + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + out << '
    ' # last row + end + + out + end +end diff --git a/hyrax/app/inputs/nested_version_input.rb b/hyrax/app/inputs/nested_version_input.rb new file mode 100644 index 00000000..d1e6be30 --- /dev/null +++ b/hyrax/app/inputs/nested_version_input.rb @@ -0,0 +1,57 @@ +class NestedVersionInput < NestedAttributesInput + +protected + + def build_components(attribute_name, value, index, options, parent=@builder.object_name) + out = '' + + # Inherit required for fields validated in nested attributes + required = false + if object.required?(:complex_version) and index == 0 + required = true + end + + # --- version + field = :version + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << '
    ' + out << '
    ' # row + + # --- date + field = :date + field_name = name_for(attribute_name, index, field, parent) + field_id = id_for(attribute_name, index, field, parent) + field_value = value.send(field).first + + out << "
    " + out << "
    " + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << '
    ' + + out << "
    " + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, + data: { provide: 'datepicker' }, required: required)) + out << '
    ' + + # --- delete checkbox + field_label = 'Version' + out << "
    " + out << destroy_widget(attribute_name, index, field_label, parent) + out << '
    ' + + out << '
    ' # last row + out + end +end diff --git a/hyrax/app/models/ability.rb b/hyrax/app/models/ability.rb index 039e44fa..58f899ac 100644 --- a/hyrax/app/models/ability.rb +++ b/hyrax/app/models/ability.rb @@ -1,8 +1,14 @@ class Ability include Hydra::Ability - - include Hyrax::Ability - self.ability_logic += [:everyone_can_create_curation_concerns] + include Hyrax::Ability # NB: not the same as the line above! + + # Registered user can only create datasets and publications + # Only admin can view the user list + self.ability_logic += [ + :read_metadata, + :create_content, + :only_admin_can_view_user_list + ] # Define any customized permissions here. def custom_permissions @@ -13,6 +19,8 @@ def custom_permissions # end if current_user.admin? can [:create, :show, :add_user, :remove_user, :index, :edit, :update, :destroy], Role + # Admin user can create works of all work types + can :create, curation_concerns_models end # Limits creating new objects to a specific group # @@ -20,4 +28,42 @@ def custom_permissions # can [:create], ActiveFedora::Base # end end + + def create_content + # only NIMS Researchers may upload new content + can :create, [::Dataset, ::Publication, ::Image] if current_user.authenticated_nims_researcher? + end + + def read_metadata + can :read_abstract, [::Dataset, ::Image, ::Publication] if current_user.authenticated? + can :read_alternative_title, [::Dataset, ::Image, ::Publication] + # NB: no users can :read_application_number + can :read_creator, [::Dataset, ::Image, ::Publication] + can :read_date, [::Dataset, ::Image, ::Publication] + can :read_event, [::Publication] + can :read_identifier, [::Dataset, ::Image, ::Publication] + can :read_issue, [::Publication] + can :read_table_of_contents, [::Publication] + can :read_keyword, [::Dataset, ::Image, ::Publication] + can :read_language, [::Dataset, ::Image, ::Publication] + can :read_location, [::Publication] + can :read_number_of_pages, [::Publication] + can :read_organization, [::Dataset, ::Publication] + can :read_publisher, [::Dataset, ::Image, ::Publication] + can :read_related, [::Dataset, ::Publication] + can :read_resource_type, [::Dataset, ::Image, ::Publication] #NB: added Dataset to list + can :read_rights, [::Dataset, ::Image, ::Publication] + can :read_source, [::Dataset, ::Publication] #NB: added Dataset to the list + can :read_subject, [::Dataset, ::Publication, ::Image] # NB: added Image to list + can :read_title, [::Dataset, ::Image, ::Publication] # NB: not used in Publication + can :read_version, [::Dataset, ::Image, ::Publication] + end + + def only_admin_can_view_user_list + if current_user.admin? + can :index, ::User + else + cannot :index, ::User + end + end end diff --git a/hyrax/app/models/concerns/common_methods.rb b/hyrax/app/models/concerns/common_methods.rb new file mode 100644 index 00000000..2bbfa4bf --- /dev/null +++ b/hyrax/app/models/concerns/common_methods.rb @@ -0,0 +1,17 @@ +module CommonMethods + extend ActiveSupport::Concern + + included do + def final_parent + parent + end + + def persisted? + !new_record? + end + + def new_record? + id.start_with?('#') + end + end +end diff --git a/hyrax/app/models/concerns/complex_affiliation.rb b/hyrax/app/models/concerns/complex_affiliation.rb new file mode 100644 index 00000000..3b790f7f --- /dev/null +++ b/hyrax/app/models/concerns/complex_affiliation.rb @@ -0,0 +1,22 @@ +class ComplexAffiliation < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::MADS.Affiliation + + property :complex_organization, predicate: ::RDF::Vocab::ORG.organization, + class_name:"ComplexOrganization" + accepts_nested_attributes_for :complex_organization + property :job_title, predicate: ::RDF::Vocab::SCHEMA.jobTitle + + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#affiliation#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_chemical_composition.rb b/hyrax/app/models/concerns/complex_chemical_composition.rb new file mode 100644 index 00000000..b0193265 --- /dev/null +++ b/hyrax/app/models/concerns/complex_chemical_composition.rb @@ -0,0 +1,20 @@ +class ComplexChemicalComposition < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['ChemicalComposition'] + property :description, predicate: ::RDF::Vocab::DC11.description + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#chemical_composition#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_crystallographic_structure.rb b/hyrax/app/models/concerns/complex_crystallographic_structure.rb new file mode 100644 index 00000000..7f8319fb --- /dev/null +++ b/hyrax/app/models/concerns/complex_crystallographic_structure.rb @@ -0,0 +1,21 @@ +class ComplexCrystallographicStructure < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['CrystallographicStructure'] + + property :description, predicate: ::RDF::Vocab::DC.description + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#crystallographic_structure#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_date.rb b/hyrax/app/models/concerns/complex_date.rb new file mode 100644 index 00000000..453a06a3 --- /dev/null +++ b/hyrax/app/models/concerns/complex_date.rb @@ -0,0 +1,17 @@ +class ComplexDate < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::VCARD.Date + property :date, predicate: ::RDF::Vocab::Bibframe.eventDate + property :description, predicate: ::RDF::Vocab::Bibframe.classification + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#date#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end +end diff --git a/hyrax/app/models/concerns/complex_event.rb b/hyrax/app/models/concerns/complex_event.rb new file mode 100644 index 00000000..73b4dd24 --- /dev/null +++ b/hyrax/app/models/concerns/complex_event.rb @@ -0,0 +1,25 @@ +class ComplexEvent < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::ESciDocPublication.Event + + property :end_date, predicate: ::RDF::Vocab::ICAL.dtend + + property :invitation_status, predicate: ::RDF::Vocab::ICAL.partstat + + property :place, predicate: ::RDF::Vocab::ESciDocPublication.place # alt: ::RDF::Vocab::ICAL.location + + property :start_date, predicate: ::RDF::Vocab::ICAL.dtstart + + property :title, predicate: ::RDF::Vocab::DC.title + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#event#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end +end diff --git a/hyrax/app/models/concerns/complex_history.rb b/hyrax/app/models/concerns/complex_history.rb new file mode 100644 index 00000000..7a632ffd --- /dev/null +++ b/hyrax/app/models/concerns/complex_history.rb @@ -0,0 +1,22 @@ +class ComplexHistory < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['History'] + property :upstream, predicate: ::RDF::Vocab::NimsRdp['upstream'] + property :downstream, predicate: ::RDF::Vocab::NimsRdp['downstream'] + property :complex_event_date, predicate: ::RDF::Vocab::Bibframe.eventDate, class_name: 'ComplexDate' + accepts_nested_attributes_for :complex_event_date + property :complex_operator, predicate: ::RDF::Vocab::SIOC.has_administrator, class_name: 'ComplexPerson' + accepts_nested_attributes_for :complex_operator + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#history#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_identifier.rb b/hyrax/app/models/concerns/complex_identifier.rb new file mode 100644 index 00000000..77e8c250 --- /dev/null +++ b/hyrax/app/models/concerns/complex_identifier.rb @@ -0,0 +1,19 @@ +class ComplexIdentifier < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::MODS.IdentifierGroup + property :identifier, predicate: ::RDF::Vocab::DataCite.hasIdentifier + property :scheme, predicate: ::RDF::Vocab::DataCite.usesIdentifierScheme + property :label, predicate: ::RDF::Vocab::SKOS.prefLabel + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#identifier#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_instrument.rb b/hyrax/app/models/concerns/complex_instrument.rb new file mode 100644 index 00000000..af81ebc5 --- /dev/null +++ b/hyrax/app/models/concerns/complex_instrument.rb @@ -0,0 +1,48 @@ +class ComplexInstrument < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['Instrument'] + + property :alternative_title, predicate: ::RDF::Vocab::DC.alternative + + property :complex_date, predicate: ::RDF::Vocab::NimsRdp["instrument-date"], + class_name:"ComplexDate" + accepts_nested_attributes_for :complex_date + + property :description, predicate: ::RDF::Vocab::DC11.description + + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + + property :instrument_function, predicate: ::RDF::Vocab::NimsRdp["instrument-function"], + class_name:"ComplexInstrumentFunction" + accepts_nested_attributes_for :instrument_function + + property :manufacturer, predicate: ::RDF::Vocab::NimsRdp["instrument-manufacturer"], + class_name:"ComplexOrganization" + accepts_nested_attributes_for :manufacturer + + property :model_number, predicate: ::RDF::Vocab::NimsRdp["instrument-model-number"] + + property :complex_person, predicate: ::RDF::Vocab::NimsRdp["instrument-operator"], + class_name:"ComplexPerson" + accepts_nested_attributes_for :complex_person + + property :managing_organization, predicate: ::RDF::Vocab::NimsRdp["instrument-organization"], + class_name:"ComplexOrganization" + accepts_nested_attributes_for :managing_organization + + property :title, predicate: ::RDF::Vocab::NimsRdp["instrument-title"] + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#instrument#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_instrument_function.rb b/hyrax/app/models/concerns/complex_instrument_function.rb new file mode 100644 index 00000000..cba859b5 --- /dev/null +++ b/hyrax/app/models/concerns/complex_instrument_function.rb @@ -0,0 +1,20 @@ +class ComplexInstrumentFunction < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['InstrumentFunction'] + property :column_number, predicate: ::RDF::Vocab::NimsRdp["column-number"] + property :category, predicate: ::RDF::Vocab::NimsRdp["category"] + property :sub_category, predicate: ::RDF::Vocab::NimsRdp["sub-category"] + property :description, predicate: ::RDF::Vocab::DC11.description + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#category_code#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_key_value.rb b/hyrax/app/models/concerns/complex_key_value.rb new file mode 100644 index 00000000..835d5136 --- /dev/null +++ b/hyrax/app/models/concerns/complex_key_value.rb @@ -0,0 +1,17 @@ +class ComplexKeyValue < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['CustomProperty'] + property :label, predicate: ::RDF::Vocab::DISCO.question + property :description, predicate: ::RDF::Vocab::SIOC.has_reply + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#key_value#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end +end diff --git a/hyrax/app/models/concerns/complex_material_type.rb b/hyrax/app/models/concerns/complex_material_type.rb new file mode 100644 index 00000000..9bada95d --- /dev/null +++ b/hyrax/app/models/concerns/complex_material_type.rb @@ -0,0 +1,22 @@ +class ComplexMaterialType < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['MaterialType'] + property :material_type, predicate: ::RDF::Vocab::NimsRdp['material-type'] + property :description, predicate: ::RDF::Vocab::DC11.description + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + property :material_sub_type, predicate: ::RDF::Vocab::NimsRdp['material-sub-type'] + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#material_type#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_organization.rb b/hyrax/app/models/concerns/complex_organization.rb new file mode 100644 index 00000000..71df0766 --- /dev/null +++ b/hyrax/app/models/concerns/complex_organization.rb @@ -0,0 +1,22 @@ +class ComplexOrganization < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::ORG.Organization + property :organization, predicate: ::RDF::Vocab::ORG.organization + property :sub_organization, predicate: ::RDF::Vocab::ORG.hasSubOrganization + property :purpose, predicate: ::RDF::Vocab::ORG.purpose + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#organization#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_person.rb b/hyrax/app/models/concerns/complex_person.rb new file mode 100644 index 00000000..0b998376 --- /dev/null +++ b/hyrax/app/models/concerns/complex_person.rb @@ -0,0 +1,28 @@ +class ComplexPerson < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::FOAF.Person + property :first_name, predicate: ::RDF::Vocab::FOAF.givenName + property :last_name, predicate: ::RDF::Vocab::FOAF.familyName + property :name, predicate: ::RDF::Vocab::VCARD.hasName + property :email, predicate: ::RDF::Vocab::FOAF.mbox + property :role, predicate: ::RDF::Vocab::MODS.roleRelationship + property :complex_affiliation, predicate: ::RDF::Vocab::VMD.affiliation, + class_name:"ComplexAffiliation" + accepts_nested_attributes_for :complex_affiliation + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + property :uri, predicate: ::RDF::Vocab::Identifiers.uri + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#person#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_purchase_record.rb b/hyrax/app/models/concerns/complex_purchase_record.rb new file mode 100644 index 00000000..4fa0d42c --- /dev/null +++ b/hyrax/app/models/concerns/complex_purchase_record.rb @@ -0,0 +1,34 @@ +class ComplexPurchaseRecord < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['PurchaseRecord'] + + property :date, predicate: ::RDF::Vocab::NimsRdp["purchase-date"] + + property :complex_identifier, predicate: ::RDF::Vocab::NimsRdp["purchase-record-identifier"], + class_name: "ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + + property :supplier, predicate: ::RDF::Vocab::NimsRdp["supplier"], + class_name: "ComplexOrganization" + accepts_nested_attributes_for :supplier + + property :manufacturer, predicate: ::RDF::Vocab::NimsRdp["manufacturer"], + class_name: "ComplexOrganization" + accepts_nested_attributes_for :manufacturer + + property :purchase_record_item, predicate: ::RDF::Vocab::NimsRdp["purchase-record-item"] + + property :title, predicate: ::RDF::Vocab::NimsRdp["purchase-record-title"] + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#purchase_record#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_relation.rb b/hyrax/app/models/concerns/complex_relation.rb new file mode 100644 index 00000000..ac55cb63 --- /dev/null +++ b/hyrax/app/models/concerns/complex_relation.rb @@ -0,0 +1,22 @@ +class ComplexRelation < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::PROV.Association + property :title, predicate: ::RDF::Vocab::DC.title + property :url, predicate: ::RDF::Vocab::MODS.locationUrl + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + property :relationship, predicate: ::RDF::Vocab::EBUCore.roleDefinition + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#relation#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_rights.rb b/hyrax/app/models/concerns/complex_rights.rb new file mode 100644 index 00000000..fd3ae62d --- /dev/null +++ b/hyrax/app/models/concerns/complex_rights.rb @@ -0,0 +1,18 @@ +class ComplexRights < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['License'] + property :date, predicate: ::RDF::Vocab::DISCO.startDate + property :rights, predicate: ::RDF::Vocab::DC.rights + property :label, predicate: ::RDF::Vocab::SKOS.prefLabel + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#rights#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end +end diff --git a/hyrax/app/models/concerns/complex_shape.rb b/hyrax/app/models/concerns/complex_shape.rb new file mode 100644 index 00000000..814dffe8 --- /dev/null +++ b/hyrax/app/models/concerns/complex_shape.rb @@ -0,0 +1,20 @@ +class ComplexShape < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['Shape'] + property :description, predicate: ::RDF::Vocab::DC11.description + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#shape#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_source.rb b/hyrax/app/models/concerns/complex_source.rb new file mode 100644 index 00000000..18044cb6 --- /dev/null +++ b/hyrax/app/models/concerns/complex_source.rb @@ -0,0 +1,31 @@ +class ComplexSource < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::ESciDocPublication.Source + + property :alternative_title, predicate: ::RDF::Vocab::DC.alternative + property :complex_person, predicate: ::RDF::Vocab::ESciDocPublication.creator, + class_name:"ComplexPerson" + accepts_nested_attributes_for :complex_person + property :end_page, predicate: ::RDF::Vocab::ESciDocPublication['end-page'] + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + property :issue, predicate: ::RDF::Vocab::ESciDocPublication.issue + property :sequence_number, predicate: ::RDF::Vocab::ESciDocPublication['sequence-number'] + property :start_page, predicate: ::RDF::Vocab::ESciDocPublication['start-page'] + property :title, predicate: ::RDF::Vocab::DC11.title + property :total_number_of_pages, predicate: ::RDF::Vocab::ESciDocPublication['total-number-of-pages'] + property :volume, predicate: ::RDF::Vocab::ESciDocPublication.volume + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#source#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_specimen_type.rb b/hyrax/app/models/concerns/complex_specimen_type.rb new file mode 100644 index 00000000..1c72fc29 --- /dev/null +++ b/hyrax/app/models/concerns/complex_specimen_type.rb @@ -0,0 +1,52 @@ +class ComplexSpecimenType < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['Specimen'] + + property :complex_chemical_composition, predicate: ::RDF::Vocab::NimsRdp["chemical-composition"], + class_name:"ComplexChemicalComposition" + accepts_nested_attributes_for :complex_chemical_composition + + property :complex_crystallographic_structure, predicate: ::RDF::Vocab::NimsRdp["crystallographic-structure"], + class_name:"ComplexCrystallographicStructure" + accepts_nested_attributes_for :complex_crystallographic_structure + + property :description, predicate: ::RDF::Vocab::DC11.description + + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + + property :complex_material_type, predicate: ::RDF::Vocab::NimsRdp["material-type"], + class_name:"ComplexMaterialType" + accepts_nested_attributes_for :complex_material_type + + property :complex_purchase_record, predicate: ::RDF::Vocab::NimsRdp["purchase-record"], + class_name:"ComplexPurchaseRecord" + accepts_nested_attributes_for :complex_purchase_record + + property :complex_shape, predicate: ::RDF::Vocab::NimsRdp["shape"], + class_name:"ComplexShape" + accepts_nested_attributes_for :complex_shape + + property :complex_state_of_matter, predicate: ::RDF::Vocab::NimsRdp["state-of-matter"], + class_name:"ComplexStateOfMatter" + accepts_nested_attributes_for :complex_state_of_matter + + property :complex_structural_feature, predicate: ::RDF::Vocab::NimsRdp["structural-feature"], + class_name:"ComplexStructuralFeature" + accepts_nested_attributes_for :complex_structural_feature + + property :title, predicate: ::RDF::Vocab::NimsRdp["specimen-title"] + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#specimen_type#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_state_of_matter.rb b/hyrax/app/models/concerns/complex_state_of_matter.rb new file mode 100644 index 00000000..5519e4ad --- /dev/null +++ b/hyrax/app/models/concerns/complex_state_of_matter.rb @@ -0,0 +1,20 @@ +class ComplexStateOfMatter < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['StateOfMatter'] + property :description, predicate: ::RDF::Vocab::DC11.description + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#state_of_matter#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_structural_feature.rb b/hyrax/app/models/concerns/complex_structural_feature.rb new file mode 100644 index 00000000..6ec83584 --- /dev/null +++ b/hyrax/app/models/concerns/complex_structural_feature.rb @@ -0,0 +1,22 @@ +class ComplexStructuralFeature < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::NimsRdp['StructuralFeature'] + property :category, predicate: ::RDF::Vocab::NimsRdp.category + property :description, predicate: ::RDF::Vocab::DC11.description + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + property :sub_category, predicate: ::RDF::Vocab::NimsRdp['sub-category'] + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#structural_feature#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end + +end diff --git a/hyrax/app/models/concerns/complex_validation.rb b/hyrax/app/models/concerns/complex_validation.rb new file mode 100644 index 00000000..eab96463 --- /dev/null +++ b/hyrax/app/models/concerns/complex_validation.rb @@ -0,0 +1,224 @@ +module ComplexValidation + extend ActiveSupport::Concern + included do + # nested_to_array + resource_class.send(:define_method, :nested_to_array) do |attributes, key| + vals = attributes.fetch(key, []) + vals = [vals] unless vals.kind_of? Array + vals + end + + # get_val_blank + resource_class.send(:define_method, :get_val_blank) do |attributes, key| + vals = nested_to_array(attributes, key) + vals.all?(&:blank?) + end + + # get_org_blank + resource_class.send(:define_method, :get_org_blank) do |attributes, key| + organization_blank = true + return true if attributes.blank? + orgs = nested_to_array(attributes, key) + puts orgs + orgs.each do |org| + vals = nested_to_array(org, :organization) + organization_blank = organization_blank && vals.all?(&:blank?) + end + organization_blank + end + + # get_dt_blank + resource_class.send(:define_method, :get_dt_blank) do |attributes, key| + date_blank = true + dates = nested_to_array(attributes, key) + dates.each do |dt| + vals = nested_to_array(dt, :date) + date_blank = date_blank && vals.all?(&:blank?) + end + date_blank + end + + # get_people_blank + resource_class.send(:define_method, :get_people_blank) do |attributes, key| + people_blank = true + people = nested_to_array(attributes, key) + people.each do |p| + first_name = nested_to_array(p, :first_name) + last_name = nested_to_array(p, :last_name) + nam = nested_to_array(p, :name) + people_blank = people_blank && + first_name.all?(&:blank?) && + last_name.all?(&:blank?) && + nam.all?(&:blank?) + end + people_blank + end + + # get_id_blank + resource_class.send(:define_method, :get_id_blank) do |attributes, key| + identifiers_blank = true + identifiers = nested_to_array(attributes, key) + identifiers.each do |id| + ids = nested_to_array(id, :identifier) + identifiers_blank = identifiers_blank && ids.all?(&:blank?) + end + identifiers_blank + end + + # affiliation_blank + # Requires job_title, organization + resource_class.send(:define_method, :affiliation_blank) do |attributes| + return true if attributes.blank? + organization_blank = get_org_blank(attributes, :complex_organization_attributes) + job_title_blank = get_val_blank(attributes, :job_title) + job_title_blank || organization_blank + end + # date_blank + # Requires date + resource_class.send(:define_method, :date_blank) do |attributes| + return true if attributes.blank? + get_val_blank(attributes, :date) + end + # history_blank + # Requires upstream or downsteam or event date or operator + resource_class.send(:define_method, :history_blank) do |attributes| + return true if attributes.blank? + date_blank = get_dt_blank(attributes, :complex_event_date_attributes) + person_blank = get_people_blank(attributes, :complex_operator_attributes) + up_blank = get_val_blank(attributes, :upstream) + down_blank = get_val_blank(attributes, :downstream) + up_blank && down_blank && date_blank && person_blank + end + # identifier_blank + # Requires identifier + resource_class.send(:define_method, :identifier_blank) do |attributes| + return true if attributes.blank? + get_val_blank(attributes, :identifier) + end + # identifier_description_blank + # Requires description, identifier + resource_class.send(:define_method, :identifier_description_blank) do |attributes| + return true if attributes.blank? + identifiers_blank = get_id_blank(attributes, :complex_identifier_attributes) + desc_blank = get_val_blank(attributes, :description) + desc_blank || identifiers_blank + end + # instrument_blank + # Requires date, identifier and person + # 27/8/2019 - temporarily remove required fields (#162) + resource_class.send(:define_method, :instrument_blank) do |attributes| + return true if attributes.blank? + # identifiers_blank = get_id_blank(attributes, :complex_identifier_attributes) + # date_blank = get_dt_blank(attributes, :complex_date_attributes) + # person_blank = get_people_blank(attributes, :complex_person_attributes) + # date_blank || identifiers_blank || person_blank + end + # key_value_blank + # Requires label and description + resource_class.send(:define_method, :key_value_blank) do |attributes| + return true if attributes.blank? + label_blank = get_val_blank(attributes, :label) + desc_blank = get_val_blank(attributes, :description) + label_blank || desc_blank + end + # organization_blank + # Requires organization + resource_class.send(:define_method, :organization_blank) do |attributes| + return true if attributes.blank? + get_val_blank(attributes, :organization) + end + # person_blank + # Requires first name or last name or name + resource_class.send(:define_method, :person_blank) do |attributes| + return true if attributes.blank? + first_name_blank = get_val_blank(attributes, :first_name) + last_name_blank = get_val_blank(attributes, :last_name) + name_blank = get_val_blank(attributes, :name) + first_name_blank && last_name_blank && name_blank + end + # purchase_record_blank + # Requires title and date + resource_class.send(:define_method, :purchase_record_blank) do |attributes| + return true if attributes.blank? + date_blank = get_val_blank(attributes, :date) + title_blank = get_val_blank(attributes, :title) + date_blank || title_blank + end + # relation_blank + # Requires title / url / identifier and relationship + resource_class.send(:define_method, :relation_blank) do |attributes| + return true if attributes.blank? + identifiers_blank = get_id_blank(attributes, :complex_identifier_attributes) + title_blank = get_val_blank(attributes, :title) + url_blank = get_val_blank(attributes, :url) + rel_blank = get_val_blank(attributes, :relationship) + (title_blank && url_blank && identifiers_blank) || rel_blank + end + # rights_blank + # Requires rights + resource_class.send(:define_method, :rights_blank) do |attributes| + return true if attributes.blank? + get_val_blank(attributes, :rights) + end + # specimen_type_blank + # Requires + # chemical_composition, crystallographic_structure, description, + # identifier, material_type, structural_feature and title + # 27/8/2019 - temporarily remove required fields (#162) + resource_class.send(:define_method, :specimen_type_blank) do |attributes| + return true if attributes.blank? + # # complex_chemical_composition blank + # cc_blank = true + # nested_to_array(attributes, :complex_chemical_composition_attributes).each do |cc| + # cc_blank = cc_blank && get_val_blank(cc, :description) + # end + # # complex_crystallographic_structure blank + # cs_blank = true + # nested_to_array(attributes, :complex_crystallographic_structure_attributes).each do |cs| + # cs_blank = cs_blank && get_val_blank(cs, :description) + # end + # # identifier blank + # id_blank = get_id_blank(attributes, :complex_identifier_attributes) + # # complex_material_type blank + # mt_blank = true + # nested_to_array(attributes, :complex_material_type_attributes).each do |mt| + # mt_blank = mt_blank && + # get_val_blank(mt, :description) && + # get_val_blank(mt, :material_type) && + # get_val_blank(mt, :material_sub_type) + # end + # # complex_structural_feature blank + # sf_blank = true + # Array(attributes[:complex_structural_feature_attributes]).each do |sf| + # sf_blank = sf_blank && + # get_val_blank(sf, :description) && + # get_val_blank(sf, :category) && + # get_val_blank(sf, :sub_category) + # end + # # description blank + # desc_blank = get_val_blank(attributes, :description) + # title blank + # title_blank = get_val_blank(attributes, :title) + # # combine them all + # cc_blank || + # cs_blank || + # desc_blank || + # id_blank || + # mt_blank || + # sf_blank || + # title_blank + end + # version_blank + # Requires version + resource_class.send(:define_method, :version_blank) do |attributes| + return true if attributes.blank? + get_val_blank(attributes, :version) + end + # event_blank + # Requires title + resource_class.send(:define_method, :event_blank) do |attributes| + return true if attributes.blank? + get_val_blank(attributes, :title) + end + end +end diff --git a/hyrax/app/models/concerns/complex_version.rb b/hyrax/app/models/concerns/complex_version.rb new file mode 100644 index 00000000..304b1d4a --- /dev/null +++ b/hyrax/app/models/concerns/complex_version.rb @@ -0,0 +1,20 @@ +class ComplexVersion < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::DOAP.Version + # ::RDF::URI.new('http://www.w3.org/2002/07/owl#versionInfo') + property :date, predicate: ::RDF::Vocab::NimsRdp["version-date"] + property :description, predicate: ::RDF::Vocab::DC.description + property :identifier, predicate: ::RDF::Vocab::NimsRdp["version-identifier"] + property :version, predicate: ::RDF::Vocab::CNT.version + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#version#{uri.to_s.gsub('_:', '')}") + elsif uri.start_with?("#") + uri = RDF::URI(uri) + end + super + end +end diff --git a/hyrax/app/models/concerns/hyrax/solr_document/mdr_export.rb b/hyrax/app/models/concerns/hyrax/solr_document/mdr_export.rb new file mode 100644 index 00000000..4eca7b4c --- /dev/null +++ b/hyrax/app/models/concerns/hyrax/solr_document/mdr_export.rb @@ -0,0 +1,9 @@ +module Hyrax + module SolrDocument + module MdrExport + def persistent_url + Rails.application.routes.url_helpers.polymorphic_url(self) + end + end + end +end diff --git a/hyrax/app/models/dataset.rb b/hyrax/app/models/dataset.rb new file mode 100644 index 00000000..b025ecb1 --- /dev/null +++ b/hyrax/app/models/dataset.rb @@ -0,0 +1,119 @@ +require "./lib/vocabularies/nims_rdp" +class Dataset < ActiveFedora::Base + include ::Hyrax::WorkBehavior + + self.indexer = DatasetIndexer + + # Change this to restrict which works can be added as a child. + # self.valid_child_concerns = [] + validates :title, presence: { message: 'Your dataset must have a title.' } + + # property date_modified - defined in core metadata + # property date_uploaded - defined in core metadata + # property depositor - defined in core metadata + # property title - defined in core metadata + # property based_near - defined in the basic metadata + # property bibliographic_citation - defined in the basic metadata + # property contributor - defined in the basic metadata + # property creator - defined in the basic metadata + # property date_created - defined in the basic metadata + # property description - defined in the basic metadata + # property identifier - defined in the basic metadata + # property import_url - defined in the basic metadata + # property keyword - defined in the basic metadata + # property label - defined in the basic metadata + # property language - defined in the basic metadata + # property publisher - defined in the basic metadata + # property related_url - defined in the basic metadata + # property relative_path - defined in the basic metadata + # property resource_type - defined in the basic metadata + # property license (rights) - defined in the basic metadata + # property rights_statement - defined in the basic metadata + # property source - defined in the basic metadata + # property subject - defined in the basic metadata + + # Required due to bug saving nested resources + property :updated_subresources, predicate: ::RDF::URI.new('http://example.com/updatedSubresources'), class_name: "ActiveTriples::Resource" + + property :alternative_title, predicate: ::RDF::Vocab::DC.alternative, multiple: false do |index| + index.as :stored_searchable + end + + property :complex_date, predicate: ::RDF::Vocab::DC.date, class_name:"ComplexDate" + + property :complex_identifier, predicate: ::RDF::Vocab::NimsRdp.identifier, class_name:"ComplexIdentifier" + + property :complex_person, predicate: ::RDF::Vocab::SIOC.has_creator, class_name:"ComplexPerson" + + property :complex_rights, predicate: ::RDF::Vocab::DC11.rights, class_name:"ComplexRights" + + property :complex_version, predicate: ::RDF::Vocab::NimsRdp.version, class_name:"ComplexVersion" + + property :complex_organization, predicate: ::RDF::Vocab::ORG.organization, class_name:"ComplexOrganization" + + property :characterization_methods, predicate: ::RDF::Vocab::NimsRdp['characterization-methods'] do |index| + index.as :stored_searchable, :facetable + end + + property :computational_methods, predicate: ::RDF::Vocab::NimsRdp['computational-methods'] do |index| + index.as :stored_searchable, :facetable + end + + # TODO - This is required + property :data_origin, predicate: ::RDF::Vocab::NimsRdp['data-origin'] do |index| + index.as :stored_searchable, :facetable + end + + property :complex_instrument, predicate: ::RDF::Vocab::NimsRdp.instrument, class_name: "ComplexInstrument" + + property :origin_system_provenance, predicate: ::RDF::Vocab::NimsRdp['origin-system-provenance'], multiple: false do |index| + index.as :stored_searchable + end + + # NOTE: Not a part of Hyrax basic metadata + # Not defining this field. It raises RSolr::Error::ConnectionRefused when added to index. + # property :part_of, predicate: ::RDF::Vocab::DC.isPartOf do |index| + # index.as :stored_searchable + # end + + property :properties_addressed, predicate: ::RDF::Vocab::NimsRdp['properties-addressed'] do |index| + index.as :stored_searchable, :facetable + end + + # Defined complex_relation in common_complex_properties in place of relation + # This could be used to describe relationships by giving more context to the relation + # could be used in place of part_of and related_url + property :complex_relation, predicate: ::RDF::Vocab::DC.relation, class_name:"ComplexRelation" + + # TODO - This is required + property :specimen_set, predicate: ::RDF::Vocab::NimsRdp['specimen-set'], multiple: false do |index| + index.as :stored_searchable + end + + property :complex_specimen_type, predicate: ::RDF::Vocab::NimsRdp['specimen-type'], + class_name: "ComplexSpecimenType" + + property :synthesis_and_processing, predicate: ::RDF::Vocab::NimsRdp['synthesis-and-processing'] do |index| + index.as :stored_searchable, :facetable + end + + property :custom_property, predicate: ::RDF::Vocab::NimsRdp['custom-property'], class_name:"ComplexKeyValue" + + property :supervisor_approval, predicate: ::RDF::Vocab::NimsRdp['supervisor-approval'] + + # This must be included at the end, because it finalizes the metadata + # schema (by adding accepts_nested_attributes) + include ::Hyrax::BasicMetadata + include ComplexValidation + accepts_nested_attributes_for :complex_date, reject_if: :date_blank, allow_destroy: true + accepts_nested_attributes_for :complex_identifier, reject_if: :identifier_blank, allow_destroy: true + accepts_nested_attributes_for :complex_instrument, reject_if: :instrument_blank, allow_destroy: true + accepts_nested_attributes_for :complex_organization, reject_if: :organization_blank, allow_destroy: true + accepts_nested_attributes_for :complex_person, reject_if: :person_blank, allow_destroy: true + accepts_nested_attributes_for :complex_relation, reject_if: :relation_blank, allow_destroy: true + accepts_nested_attributes_for :complex_rights, reject_if: :rights_blank, allow_destroy: true + accepts_nested_attributes_for :complex_specimen_type, reject_if: :specimen_type_blank, allow_destroy: true + accepts_nested_attributes_for :complex_version, reject_if: :version_blank, allow_destroy: true + accepts_nested_attributes_for :custom_property, reject_if: :key_value_blank, allow_destroy: true + accepts_nested_attributes_for :updated_subresources, allow_destroy: true +end diff --git a/hyrax/app/models/doi.rb b/hyrax/app/models/doi.rb new file mode 100644 index 00000000..7d78764e --- /dev/null +++ b/hyrax/app/models/doi.rb @@ -0,0 +1,40 @@ +class DOI + attr_reader :identifier + + DOI_URL_REGEXP = /^https?\:\/\/(?:dx\.)?doi\.org\/(.+)$/i + DOI_PREFIX_REGEXP = /^doi\:(?:\s*)(.+)$/i + INFO_DOI_PREFIX_REGEXP = /^info\:(?:\s*)doi\/(.+)$/i + + def initialize(value) + # Example valid DOIs which should be parsed: + # * 10.5555/12345678 + # * doi:10.5555/12345678 + # * info:doi/10.5555/12345678 # from RFC4452 + # * http://dx.doi.org/10.5555/12345678 + # * https://doi.org/10.5555/12345678 + # * 10/hvx + # * doi:10/hvx + # * http://doi.org/hvx + + # check if the value has a doi: or url prefix, and if so, extract the raw doi + if (match = DOI.match_doi_prefix(value)) + @identifier = match.captures.first + else + # the value is not a doi URL or prefixed with doi: or info:doi/, so just assume it is a raw doi + @identifier = value + end + end + + def url + "https://doi.org/#{@identifier}" + end + + def label + "doi:#{@identifier}" + end + + def self.match_doi_prefix(value) + return nil unless value.is_a?(String) && value.present? + value.match(DOI_URL_REGEXP) || value.match(DOI_PREFIX_REGEXP) || value.match(INFO_DOI_PREFIX_REGEXP) + end +end diff --git a/hyrax/app/models/file_set.rb b/hyrax/app/models/file_set.rb index 393de0ee..1cb99abe 100644 --- a/hyrax/app/models/file_set.rb +++ b/hyrax/app/models/file_set.rb @@ -1,4 +1,32 @@ # Generated by hyrax:models:install class FileSet < ActiveFedora::Base + property :date_copyrighted, predicate: ::RDF::Vocab::DC.dateCopyrighted do |index| + index.as :stored_searchable, type: :date + end + include ::Hyrax::FileSetBehavior + + # override method in lib/hydra/works/models/concerns/file_set/mime_types.rb + # add text/plain + def self.office_document_mime_types + [ + 'text/plain', + 'text/csv', + 'text/tab-separated-values', + 'text/rtf', + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.oasis.opendocument.text', + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.ms-powerpoint', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' + ] + end + + def text? + ['text/plain', + 'text/csv', + 'text/tab-separated-values'].include? mime_type + end end diff --git a/hyrax/app/models/handle.rb b/hyrax/app/models/handle.rb new file mode 100644 index 00000000..a8751836 --- /dev/null +++ b/hyrax/app/models/handle.rb @@ -0,0 +1,37 @@ +class Handle + attr_reader :identifier + + HDL_URL_REGEXP = /^https?\:\/\/(?:hdl\.)?handle\.net\/(.+)$/i + HDL_PREFIX_REGEXP = /^hdl\:(?:\s*)(.+)$/i + INFO_HDL_PREFIX_REGEXP = /^info\:(?:\s*)hdl\/(.+)$/i + + def initialize(value) + # Example valid Handles which should be parsed: + # * 4263537/400 + # * hdl:4263537/400 + # * info:hdl/4263537/400 # from RFC4452 + # * http://hdl.handle.net/4263537/400 + # * https://hdl.handle.net/4263537/400 + + # check if the value has a hdl: or url prefix, and if so, extract the raw handle + if (match = Handle.match_hdl_prefix(value)) + @identifier = match.captures.first + else + # the value is not a handle URL or prefixed with hdl: or info:hdl/, so just assume it is a raw handle + @identifier = value + end + end + + def url + "https://hdl.handle.net/#{@identifier}" + end + + def label + "hdl:#{@identifier}" + end + + def self.match_hdl_prefix(value) + return nil unless value.is_a?(String) && value.present? + value.match(HDL_URL_REGEXP) || value.match(HDL_PREFIX_REGEXP) || value.match(INFO_HDL_PREFIX_REGEXP) + end +end diff --git a/hyrax/app/models/image.rb b/hyrax/app/models/image.rb new file mode 100644 index 00000000..1224c16f --- /dev/null +++ b/hyrax/app/models/image.rb @@ -0,0 +1,94 @@ +# Generated via +# `rails generate hyrax:work Image` +class Image < ActiveFedora::Base + include ::Hyrax::WorkBehavior + + self.indexer = ImageIndexer + # Change this to restrict which works can be added as a child. + # self.valid_child_concerns = [] + validates :title, presence: { message: 'Your image must have a title.' } + + # property date_modified - defined in core metadata + # property date_uploaded - defined in core metadata + # property depositor - defined in core metadata + # property title - defined in core metadata + # property based_near - defined in the basic metadata + # property bibliographic_citation - defined in the basic metadata + # property contributor - defined in the basic metadata + # property creator - defined in the basic metadata + # property date_created - defined in the basic metadata + # property description - defined in the basic metadata + # property identifier - defined in the basic metadata + # property import_url - defined in the basic metadata + # property keyword - defined in the basic metadata + # property label - defined in the basic metadata + # property language - defined in the basic metadata + # property publisher - defined in the basic metadata + # property related_url - defined in the basic metadata + # property relative_path - defined in the basic metadata + # property resource_type - defined in the basic metadata + # property license (rights) - defined in the basic metadata + # property rights_statement - defined in the basic metadata + # property source - defined in the basic metadata + # property subject - defined in the basic metadata + + + # NOTE: Not a part of Hyrax basic metadata + # Not defining this field. It raises RSolr::Error::ConnectionRefused when added to index. + # property :part_of, predicate: ::RDF::Vocab::DC.isPartOf do |index| + # index.as :stored_searchable + # end + + # NGDR Hyrax Work Common + property :alternative_title, predicate: ::RDF::Vocab::DC.alternative, multiple: false do |index| + index.as :stored_searchable + end + + property :complex_date, predicate: ::RDF::Vocab::DC.date, class_name: 'ComplexDate' + + property :complex_identifier, predicate: ::RDF::Vocab::NimsRdp.identifier, class_name: 'ComplexIdentifier' + + property :complex_person, predicate: ::RDF::Vocab::SIOC.has_creator, class_name: 'ComplexPerson' + + # Required due to bug saving nested resources + property :updated_subresources, predicate: ::RDF::URI.new('http://example.com/updatedSubresources'), class_name: "ActiveTriples::Resource" + + # TODO: Need more information + # property :complex_license, predicate: ::RDF::URI.new('http://www.niso.org/schemas/ali/1.0/license_ref'), class_name:'ComplexLicense' + + property :complex_rights, predicate: ::RDF::Vocab::DC11.rights, class_name: 'ComplexRights' + + property :complex_version, predicate: ::RDF::Vocab::NimsRdp.version, class_name: 'ComplexVersion' + + property :status, predicate: ::RDF::Vocab::BIBO.status, multiple: false do |index| + index.as :stored_searchable, :facetable + end + + # NGDR Hyrax Work Image MVP + # Note: all date fields are covered by complex_date in Hyrax Work Common above + property :instrument, predicate: ::RDF::Vocab::NimsRdp.instrument do |index| + index.as :stored_searchable, :facetable + end + + property :specimen_set, predicate: ::RDF::Vocab::NimsRdp['specimen-set'] do |index| + index.as :stored_searchable, :facetable + end + + property :complex_relation, predicate: ::RDF::Vocab::DC.relation, class_name:"ComplexRelation" + + property :custom_property, predicate: ::RDF::Vocab::NimsRdp['custom-property'], class_name:"ComplexKeyValue" + + # This must be included at the end, because it finalizes the metadata + # schema (by adding accepts_nested_attributes) + include ::Hyrax::BasicMetadata + include ComplexValidation + accepts_nested_attributes_for :complex_date, reject_if: :date_blank, allow_destroy: true + accepts_nested_attributes_for :complex_identifier, reject_if: :identifier_blank, allow_destroy: true + # accepts_nested_attributes_for :complex_license, reject_if: :license_blank, allow_destroy: true + accepts_nested_attributes_for :complex_person, reject_if: :person_blank, allow_destroy: true + accepts_nested_attributes_for :complex_rights, reject_if: :rights_blank, allow_destroy: true + accepts_nested_attributes_for :complex_version, reject_if: :version_blank, allow_destroy: true + accepts_nested_attributes_for :complex_relation, reject_if: :relation_blank, allow_destroy: true + accepts_nested_attributes_for :custom_property, reject_if: :key_value_blank, allow_destroy: true + accepts_nested_attributes_for :updated_subresources, allow_destroy: true +end diff --git a/hyrax/app/models/nims_roles.rb b/hyrax/app/models/nims_roles.rb new file mode 100644 index 00000000..7ef9c30b --- /dev/null +++ b/hyrax/app/models/nims_roles.rb @@ -0,0 +1,36 @@ +module NIMSRoles + def authenticated_nims_researcher? + unless defined?(@authenticated_nims_researcher) + if !guest? && employee_type_code.present? && employee_type_code =~ /^(A|G|L|Q|R|S)/i + @authenticated_nims_researcher = true + else + @authenticated_nims_researcher = false + end + end + @authenticated_nims_researcher + end + + def authenticated_nims_other? + unless defined?(@authenticated_nims_other) + if !guest? && employee_type_code.present? && employee_type_code =~ /^(T|Z)/i + @authenticated_nims_other = true + else + @authenticated_nims_other = false + end + end + @authenticated_nims_other + end + + def authenticated_nims? + authenticated_nims_researcher? || authenticated_nims_other? + end + + def authenticated_external? + # Coming in Phase 3 (June 2020) + false + end + + def authenticated? + authenticated_nims? || authenticated_external? + end +end diff --git a/hyrax/app/models/publication.rb b/hyrax/app/models/publication.rb new file mode 100644 index 00000000..c442bff2 --- /dev/null +++ b/hyrax/app/models/publication.rb @@ -0,0 +1,101 @@ +require './lib/vocabularies/escidoc_publication' + +class Publication < ActiveFedora::Base + include ::Hyrax::WorkBehavior + + self.indexer = PublicationIndexer + # Change this to restrict which works can be added as a child. + # self.valid_child_concerns = [] + validates :title, presence: { message: 'Your publication must have a title.' } + + # property date_modified - defined in core metadata + # property date_uploaded - defined in core metadata + # property depositor - defined in core metadata + # property title - defined in core metadata + # property based_near - defined in the basic metadata + # property bibliographic_citation - defined in the basic metadata + # property contributor - defined in the basic metadata + # property creator - defined in the basic metadata + # property date_created - defined in the basic metadata + # property description - defined in the basic metadata + # property identifier - defined in the basic metadata + # property import_url - defined in the basic metadata + # property keyword - defined in the basic metadata + # property label - defined in the basic metadata + # property language - defined in the basic metadata + # property publisher - defined in the basic metadata + # property related_url - defined in the basic metadata + # property relative_path - defined in the basic metadata + # property resource_type - defined in the basic metadata + # property license (rights) - defined in the basic metadata + # property rights_statement - defined in the basic metadata + # property source - defined in the basic metadata + # property subject - defined in the basic metadata + + + # NOTE: Not a part of Hyrax basic metadata + # Not defining this field. It raises RSolr::Error::ConnectionRefused when added to index. + # property :part_of, predicate: ::RDF::Vocab::DC.isPartOf do |index| + # index.as :stored_searchable + # end + + # Required due to bug saving nested resources + property :updated_subresources, predicate: ::RDF::URI.new('http://example.com/updatedSubresources'), class_name: "ActiveTriples::Resource" + + # NGDR Hyrax Work Common + property :alternative_title, predicate: ::RDF::Vocab::DC.alternative, multiple: false do |index| + index.as :stored_searchable + end + + property :complex_date, predicate: ::RDF::Vocab::DC.date, class_name: 'ComplexDate' + + property :complex_identifier, predicate: ::RDF::Vocab::NimsRdp.identifier, class_name: 'ComplexIdentifier' + + property :complex_person, predicate: ::RDF::Vocab::SIOC.has_creator, class_name: 'ComplexPerson' + + # TODO: Need more information + # property :complex_license, predicate: ::RDF::URI.new('http://www.niso.org/schemas/ali/1.0/license_ref'), class_name:'ComplexLicense' + + property :complex_rights, predicate: ::RDF::Vocab::DC11.rights, class_name: 'ComplexRights' + + property :complex_version, predicate: ::RDF::Vocab::NimsRdp.version, class_name: 'ComplexVersion' + + # NGDR Hyrax Work Publication MVP + # Note: all date fields are covered by complex_date in Hyrax Work Common above + + property :complex_event, predicate: ::RDF::Vocab::ESciDocPublication.event, class_name: 'ComplexEvent' + + property :issue, predicate: ::RDF::Vocab::ESciDocPublication.issue, multiple: false do |index| + index.as :stored_searchable + end + + property :place, predicate: ::RDF::Vocab::ESciDocPublication.place, multiple: false do |index| + index.as :stored_searchable, :facetable + end + + property :table_of_contents, predicate: ::RDF::Vocab::DC.tableOfContents, multiple: false do |index| + index.as :stored_searchable + end + + property :total_number_of_pages, predicate: ::RDF::Vocab::ESciDocPublication['total-number-of-pages'], multiple: false do |index| + index.as :stored_searchable, :sortable, type: :integer + end + + property :complex_source, predicate: ::RDF::Vocab::ESciDocPublication.source, class_name: 'ComplexSource' + + property :supervisor_approval, predicate: ::RDF::Vocab::NimsRdp['supervisor-approval'] + + # This must be included at the end, because it finalizes the metadata + # schema (by adding accepts_nested_attributes) + include ::Hyrax::BasicMetadata + include ComplexValidation + accepts_nested_attributes_for :complex_date, reject_if: :date_blank, allow_destroy: true + accepts_nested_attributes_for :complex_identifier, reject_if: :identifier_blank, allow_destroy: true + # accepts_nested_attributes_for :complex_license, reject_if: :license_blank, allow_destroy: true + accepts_nested_attributes_for :complex_person, reject_if: :person_blank, allow_destroy: true + accepts_nested_attributes_for :complex_rights, reject_if: :rights_blank, allow_destroy: true + accepts_nested_attributes_for :complex_version, reject_if: :version_blank, allow_destroy: true + accepts_nested_attributes_for :complex_event, reject_if: :event_blank, allow_destroy: true + accepts_nested_attributes_for :complex_source, reject_if: :all_blank, allow_destroy: true + accepts_nested_attributes_for :updated_subresources, allow_destroy: true +end diff --git a/hyrax/app/models/solr_document.rb b/hyrax/app/models/solr_document.rb index d8673266..9745e68f 100644 --- a/hyrax/app/models/solr_document.rb +++ b/hyrax/app/models/solr_document.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true class SolrDocument include Blacklight::Solr::Document + include BlacklightOaiProvider::SolrDocumentBehavior include Blacklight::Gallery::OpenseadragonSolrDocument # Adds Hyrax behaviors to the SolrDocument. include Hyrax::SolrDocumentBehavior - + include Hyrax::SolrDocument::MdrExport # self.unique_key = 'id' @@ -22,7 +23,129 @@ class SolrDocument # Recommendation: Use field names from Dublin Core use_extension(Blacklight::Document::DublinCore) - # Do content negotiation for AF models. + # Add field_semantics for oai_dc + field_semantics.merge!( + contributor: 'complex_person_other_tesim', # @todo - extract anything other than author from complex person, may need new solr field + creator: 'complex_person_author_tesim', + date: 'date_tesim', + description: 'description_tesim', + identifier: 'complex_identifier_tesim', + language: 'language_tesim', + publisher: 'publisher_tesim', + relation: '', # @todo have a think about what to map here + rights: 'rights_tesim', + subject: 'subject_tesim', + title: 'title_tesim', + type: 'resource_type_tesim' + ) + + + # Do content negotiation for AF models. use_extension( Hydra::ContentNegotiation ) + + def alternative_title + self[Solrizer.solr_name('alternative_title', :stored_searchable)] + end + + def complex_date + self[Solrizer.solr_name('complex_date', :displayable)] + end + + def complex_identifier + self[Solrizer.solr_name('complex_identifier', :displayable)] + end + + def complex_instrument + self[Solrizer.solr_name('complex_instrument', :displayable)] + end + + def complex_organization + self[Solrizer.solr_name('complex_organization', :displayable)] + end + + def complex_person + self[Solrizer.solr_name('complex_person', :displayable)] + end + + def complex_rights + self[Solrizer.solr_name('complex_rights', :displayable)] + end + + def complex_specimen_type + self[Solrizer.solr_name('complex_specimen_type', :displayable)] + end + + def complex_version + self[Solrizer.solr_name('complex_version', :displayable)] + end + + def characterization_methods + self[Solrizer.solr_name('characterization_methods', :stored_searchable)] + end + + def computational_methods + self[Solrizer.solr_name('computational_methods', :stored_searchable)] + end + + def data_origin + self[Solrizer.solr_name('data_origin', :stored_searchable)] + end + + def instrument + self[Solrizer.solr_name('instrument', :stored_searchable)] + end + + def origin_system_provenance + self[Solrizer.solr_name('origin_system_provenance', :stored_searchable)] + end + + def properties_addressed + self[Solrizer.solr_name('properties_addressed', :stored_searchable)] + end + + def complex_relation + self[Solrizer.solr_name('complex_relation', :displayable)] + end + + def specimen_set + self[Solrizer.solr_name('specimen_set', :stored_searchable)] + end + + def synthesis_and_processing + self[Solrizer.solr_name('synthesis_and_processing', :stored_searchable)] + end + + def custom_property + self[Solrizer.solr_name('custom_property', :displayable)] + end + + def complex_event + self[Solrizer.solr_name('complex_event', :displayable)] + end + + def issue + self[Solrizer.solr_name('issue', :stored_searchable)] + end + + def place + self[Solrizer.solr_name('place', :stored_searchable)] + end + + def table_of_contents + self[Solrizer.solr_name('table_of_contents', :stored_searchable)] + end + + def total_number_of_pages + self[Solrizer.solr_name('total_number_of_pages', :stored_searchable)] + end + + def complex_source + self[Solrizer.solr_name('complex_source', :displayable)] + end + + def status + self[Solrizer.solr_name('status', :stored_searchable)] + end end + diff --git a/hyrax/app/models/user.rb b/hyrax/app/models/user.rb index 22e9ee06..56f4c76d 100644 --- a/hyrax/app/models/user.rb +++ b/hyrax/app/models/user.rb @@ -3,28 +3,48 @@ class User < ApplicationRecord include Hydra::User # Connects this user object to Role-management behaviors. include Hydra::RoleManagement::UserRoles - + include NIMSRoles # Connects this user object to Hyrax behaviors. include Hyrax::User include Hyrax::UserUsageStats - + has_many :uploaded_files, class_name: 'Hyrax::UploadedFile', dependent: :nullify if Blacklight::Utils.needs_attr_accessible? - attr_accessible :email, :password, :password_confirmation + attr_accessible :username, :email, :password, :password_confirmation end # Connects this user object to Blacklights Bookmarks. include Blacklight::User # Include default devise modules. Others available are: - # :confirmable, :lockable, :timeoutable and :omniauthable - devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :trackable, :validatable + # :registerable, :confirmable, :lockable, :timeoutable and :omniauthable + devise ENV.fetch('MDR_DEVISE_AUTH_MODULE', 'database_authenticatable').to_sym, + :rememberable, :trackable, :lockable + # NB: the :validatable module is not compatible with CAS authentication # Method added by Blacklight; Blacklight uses #to_s on your # user class to get a user-displayable login/identifier for # the account. def to_s - email + display_name + end + + def self.find_or_create_system_user(user_key) + username = user_key.split('@')[0] + User.find_by('email' => user_key) || User.create!(username: username, email: user_key, password: Devise.friendly_token[0, 20], user_identifier: Noid::Rails::Service.new.mint) + end + + def ldap_before_save + # Runs before saving a new user record in the database via LDAP Authentication + self.email = Devise::LDAP::Adapter.get_ldap_param(username, "mail").first + self.display_name = Devise::LDAP::Adapter.get_ldap_param(username, "cn").first + self.employee_type_code = Devise::LDAP::Adapter.get_ldap_param(username, "employeeType").first.try(:first) + self.password = Devise.friendly_token[0, 20] + # TODO: This will be replaced by NIMS PID when the CAS server is online + self.user_identifier = Noid::Rails::Service.new.mint + end + + def self.from_url_component(component) + User.find_by(user_identifier: component) || User.find_by_user_key(component.gsub(/-dot-/, '.')) end end diff --git a/hyrax/app/patches/devise_cas_authenticatable/single_sign_out/destroy_session.rb b/hyrax/app/patches/devise_cas_authenticatable/single_sign_out/destroy_session.rb new file mode 100644 index 00000000..c57c772a --- /dev/null +++ b/hyrax/app/patches/devise_cas_authenticatable/single_sign_out/destroy_session.rb @@ -0,0 +1,18 @@ +# Monkey Patch to DeviseCasAuthenticatable::SingleSignOut::DestroySession#destroy_session_by_id to fix env issue + +module DeviseCasAuthenticatable + module SingleSignOut + module DestroySession + def destroy_session_by_id(sid) + logger.debug "Single Sign Out from session store: #{current_session_store.class}" + if session_store_class.name =~ /RedisSessionStore/ + current_session_store.send(:destroy_session, {}, sid, drop: true) + true + else + logger.error "Unsupported session store: #{session_store_class.name}" + false + end + end + end + end +end diff --git a/hyrax/app/presenters/hyrax/dataset_presenter.rb b/hyrax/app/presenters/hyrax/dataset_presenter.rb new file mode 100644 index 00000000..ffca8c9f --- /dev/null +++ b/hyrax/app/presenters/hyrax/dataset_presenter.rb @@ -0,0 +1,14 @@ +# Generated via +# `rails generate hyrax:work Dataset` +module Hyrax + class DatasetPresenter < Hyrax::WorkShowPresenter + delegate :alternative_title, :complex_date, :complex_identifier, + :complex_person, :complex_organization, :complex_rights, :complex_version, + :characterization_methods, :computational_methods, :data_origin, + :complex_instrument, :origin_system_provenance, :properties_addressed, + :complex_relation, :specimen_set, :complex_specimen_type, + :synthesis_and_processing, :custom_property, to: :solr_document + + Hyrax::MemberPresenterFactory.file_presenter_class = Hyrax::NimsFileSetPresenter + end +end diff --git a/hyrax/app/presenters/hyrax/image_presenter.rb b/hyrax/app/presenters/hyrax/image_presenter.rb new file mode 100644 index 00000000..dbf70f16 --- /dev/null +++ b/hyrax/app/presenters/hyrax/image_presenter.rb @@ -0,0 +1,11 @@ +# Generated via +# `rails generate hyrax:work Image` +module Hyrax + class ImagePresenter < Hyrax::WorkShowPresenter + delegate :alternative_title, :complex_date, :complex_identifier, :complex_person, + :complex_rights, :complex_version, :status, :specimen_set, :instrument, + :complex_relation, :custom_property, to: :solr_document + + Hyrax::MemberPresenterFactory.file_presenter_class = Hyrax::NimsFileSetPresenter + end +end diff --git a/hyrax/app/presenters/hyrax/nims_file_set_presenter.rb b/hyrax/app/presenters/hyrax/nims_file_set_presenter.rb new file mode 100644 index 00000000..2abc83a6 --- /dev/null +++ b/hyrax/app/presenters/hyrax/nims_file_set_presenter.rb @@ -0,0 +1,18 @@ +# special extension of the default FileSetPresenter to cater for CSV files +module Hyrax + class NimsFileSetPresenter < FileSetPresenter + + def mime_type + solr_document.mime_type if solr_document.present? && solr_document.respond_to?(:mime_type) + end + + def csv? + if mime_type.present? && mime_type =~ /^(?:text|application)\/csv$/i + true + else + false + end + end + + end +end diff --git a/hyrax/app/presenters/hyrax/publication_presenter.rb b/hyrax/app/presenters/hyrax/publication_presenter.rb new file mode 100644 index 00000000..0d37cbad --- /dev/null +++ b/hyrax/app/presenters/hyrax/publication_presenter.rb @@ -0,0 +1,11 @@ +# Generated via +# `rails generate hyrax:work Publication` +module Hyrax + class PublicationPresenter < Hyrax::WorkShowPresenter + delegate :alternative_title, :complex_date, :complex_identifier, :complex_person, + :complex_rights, :complex_version, :complex_event, :issue, :place, + :table_of_contents, :total_number_of_pages, :complex_source, to: :solr_document + + Hyrax::MemberPresenterFactory.file_presenter_class = Hyrax::NimsFileSetPresenter + end +end diff --git a/hyrax/app/presenters/hyrax/work_presenter.rb b/hyrax/app/presenters/hyrax/work_presenter.rb index 71535ec2..21150234 100644 --- a/hyrax/app/presenters/hyrax/work_presenter.rb +++ b/hyrax/app/presenters/hyrax/work_presenter.rb @@ -2,5 +2,6 @@ # `rails generate hyrax:work Work` module Hyrax class WorkPresenter < Hyrax::WorkShowPresenter + Hyrax::MemberPresenterFactory.file_presenter_class = Hyrax::NimsFileSetPresenter end end diff --git a/hyrax/app/renderers/nested_affiliation_attribute_renderer.rb b/hyrax/app/renderers/nested_affiliation_attribute_renderer.rb new file mode 100644 index 00000000..851c73cc --- /dev/null +++ b/hyrax/app/renderers/nested_affiliation_attribute_renderer.rb @@ -0,0 +1,23 @@ +class NestedAffiliationAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + unless v.dig('job_title').blank? + label = "Job title" + val = v['job_title'][0] + each_html += get_row(label, val) + end + unless v.dig('complex_organization').blank? + label = 'Organization' + renderer_class = NestedOrganizationAttributeRenderer + each_html += get_nested_output(field, label, v['complex_organization'], renderer_class, false) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_attribute_renderer.rb b/hyrax/app/renderers/nested_attribute_renderer.rb new file mode 100644 index 00000000..f96a028c --- /dev/null +++ b/hyrax/app/renderers/nested_attribute_renderer.rb @@ -0,0 +1,124 @@ +class NestedAttributeRenderer < Hyrax::Renderers::FacetedAttributeRenderer + + # Draw the dl row for the attribute + def render_dl_row + markup = '' + return markup if values.blank? && !options[:include_empty] + inner_markup = '' + attributes = microdata_object_attributes(field).merge(class: "attribute attribute-#{field}") + Array(values).each do |value| + inner_text = attribute_value_to_html(value.to_s) + inner_markup << "#{inner_text}" if inner_text.present? + end + if !options[:include_empty] and inner_markup.present? + markup << %(
    #{label}
    \n
      ) + markup << inner_markup + markup << %(
    ) + end + markup.html_safe + end + + private + + def parse_value(value) + if value.kind_of?(String) + value = JSON.parse(value) + end + unless value.kind_of?(Array) + value = [value] + end + value + end + + def get_row(label, val) + row = '' + return row if val.blank? + row += '
    ' + row += "
    " + if label =~ /^doi$/i || DOI.match_doi_prefix(val) + row += "
    #{get_doi_hyperlink(val)}
    " + elsif Handle.match_hdl_prefix(val) + row += "
    #{get_handle_hyperlink(val)}
    " + else + row += "
    #{val}
    " + end + row += "
    " + row + end + + def get_label_row(label) + row = '' + row += '
    ' + row += "
    " + row += "
    " + row + end + + def get_doi_hyperlink(val) + doi = DOI.new(val) + link_to(doi.label, doi.url, target: '_blank') + end + + def get_handle_hyperlink(val) + handle = Handle.new(val) + link_to(handle.label, handle.url, target: '_blank') + end + + def get_nested_output(field, label, nested_value, renderer_class, display_label=false) + output_html = '' + unless nested_value.kind_of?(Array) + nested_value = [nested_value] + end + renderer = renderer_class.new(get_field(field, label), nested_value) + nested_value.each do |val| + inner_html = renderer.attribute_value_to_html(val) + unless inner_html.blank? + output_html += get_label_row(label) if display_label + output_html += inner_html + end + end + output_html + end + + def get_inner_html(html) + html_out = '' + unless html.blank? + html_out = '' + end + html_out + end + + def get_ouput_html(html) + html_out = '' + unless html.blank? + html_out = '' + end + html_out + end + + # map the field/label pair to the correct facet search link + def get_field(field, label) + case + when field == :complex_person && label == 'Organization' + :complex_person_organization + when field == :complex_instrument && label == 'Manufacturer' + :instrument_manufacturer + when field == :complex_instrument && label == 'Operator' + :complex_person_operator + when field == :complex_instrument && label == 'Managing organization' + :instrument_managing_organization + when field == :complex_specimen_type && label == 'Supplier' + :complex_purchase_record_supplier + when field == :complex_specimen_type && label == 'Manufacturer' + :complex_purchase_record_manufacturer + when field == :complex_person_operator && label == 'Organization' + :complex_person_operator_organization + else + field + end + end +end diff --git a/hyrax/app/renderers/nested_custom_property_attribute_renderer.rb b/hyrax/app/renderers/nested_custom_property_attribute_renderer.rb new file mode 100644 index 00000000..2530ae37 --- /dev/null +++ b/hyrax/app/renderers/nested_custom_property_attribute_renderer.rb @@ -0,0 +1,20 @@ +class NestedCustomPropertyAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + label = '' + val = '' + unless v.dig('label').blank? + label = v['label'][0] + end + unless v.dig('description').blank? + val = v['description'][0] + end + html += get_row(label, val) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_date_attribute_renderer.rb b/hyrax/app/renderers/nested_date_attribute_renderer.rb new file mode 100644 index 00000000..7e5b148e --- /dev/null +++ b/hyrax/app/renderers/nested_date_attribute_renderer.rb @@ -0,0 +1,26 @@ +class NestedDateAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + label = 'Date' + val = '' + if v.dig('description').present? and v['description'][0].present? + label = v['description'][0] + term = DateService.new.find_by_id(label) + label = term['label'] if term.any? + end + if v.dig('date').present? and v['date'][0].present? + begin + val = Date.parse(v['date'][0]).to_formatted_s(:standard) + rescue ArgumentError + val = v['date'][0] + end + end + html += get_row(label, val) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_desc_id_attribute_renderer.rb b/hyrax/app/renderers/nested_desc_id_attribute_renderer.rb new file mode 100644 index 00000000..ec195731 --- /dev/null +++ b/hyrax/app/renderers/nested_desc_id_attribute_renderer.rb @@ -0,0 +1,23 @@ +class NestedDescIdAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + unless v.dig('description').blank? + label = "Description" + val = v['description'][0] + each_html += get_row(label, val) + end + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_event_attribute_renderer.rb b/hyrax/app/renderers/nested_event_attribute_renderer.rb new file mode 100644 index 00000000..bc25c8b0 --- /dev/null +++ b/hyrax/app/renderers/nested_event_attribute_renderer.rb @@ -0,0 +1,38 @@ +class NestedEventAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + unless v.dig('title').blank? + label = 'Title' + val = v['title'][0] + each_html += get_row(label, val) + end + unless v.dig('place').blank? + label = 'Location' + val = v['place'][0] + each_html += get_row(label, val) + end + unless v.dig('start_date').blank? + label = 'Start date' + val = v['start_date'][0] + each_html += get_row(label, val) + end + unless v.dig('end_date').blank? + label = 'End date' + val = v['end_date'][0] + each_html += get_row(label, val) + end + unless v.dig('invitation_status').blank? + label = 'Invitation status' + val = v['invitation_status'][0] + each_html += get_row(label, val) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_identifier_attribute_renderer.rb b/hyrax/app/renderers/nested_identifier_attribute_renderer.rb new file mode 100644 index 00000000..8d16754c --- /dev/null +++ b/hyrax/app/renderers/nested_identifier_attribute_renderer.rb @@ -0,0 +1,22 @@ +class NestedIdentifierAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + scheme = 'Identifier' + val = '' + unless v.dig('scheme').blank? + scheme = v['scheme'][0] + term = IdentifierService.new.find_by_id(v['scheme'][0]) + scheme = term['label'] if term.any? + end + unless v.dig('identifier').blank? + val = v['identifier'][0] + end + html += get_row(scheme, val) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_instrument_attribute_renderer.rb b/hyrax/app/renderers/nested_instrument_attribute_renderer.rb new file mode 100644 index 00000000..1212b47c --- /dev/null +++ b/hyrax/app/renderers/nested_instrument_attribute_renderer.rb @@ -0,0 +1,74 @@ +class NestedInstrumentAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # title + if v.dig('title').present? and v['title'][0].present? + label ="Title" + # @todo - fixme + val = link_to(ERB::Util.h(v['title'][0]), search_path(v['title'][0])) + each_html += get_row(label, val) + end + # alternative title + unless v.dig('alternative_title').blank? + label = 'Alternative title' + val = v['alternative_title'][0] + each_html += get_row(label, val) + end + # complex date + unless v.dig('complex_date').blank? + label = 'Date' + renderer_class = NestedDateAttributeRenderer + each_html += get_nested_output(field, label, v['complex_date'], renderer_class, false) + end + # description + unless v.dig('description').blank? + label = 'Description' + val = v['description'][0] + each_html += get_row(label, val) + end + # complex identifier + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + # instrument function + unless v.dig('instrument_function').blank? + label = 'Instrument function' + renderer_class = NestedInstrumentFunctionAttributeRenderer + each_html += get_nested_output(field, label, v['instrument_function'], renderer_class, true) + end + # manufacturer + unless v.dig('manufacturer').blank? + label = 'Manufacturer' + renderer_class = NestedOrganizationAttributeRenderer + each_html += get_nested_output(field, label, v['manufacturer'], renderer_class, true) + end + # model_number + unless v.dig('model_number').blank? + label = 'Model number' + val = v['model_number'][0] + each_html += get_row(label, val) + end + # compex_person + unless v.dig('complex_person').blank? + label = 'Operator' + renderer_class = NestedPersonAttributeRenderer + each_html += get_nested_output(field, label, v['complex_person'], renderer_class, true) + end + # managing_organization + unless v.dig('managing_organization').blank? + label = 'Managing organization' + renderer_class = NestedOrganizationAttributeRenderer + each_html += get_nested_output(field, label, v['managing_organization'], renderer_class, true) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_instrument_function_attribute_renderer.rb b/hyrax/app/renderers/nested_instrument_function_attribute_renderer.rb new file mode 100644 index 00000000..8d6a5965 --- /dev/null +++ b/hyrax/app/renderers/nested_instrument_function_attribute_renderer.rb @@ -0,0 +1,37 @@ +class NestedInstrumentFunctionAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # column_number + unless v.dig('column_number').blank? + label ="Column number" + val = v['column_number'][0] + each_html += get_row(label, val) + end + # category + unless v.dig('category').blank? + label ="Category" + val = v['category'][0] + each_html += get_row(label, val) + end + # sub_category + unless v.dig('sub_category').blank? + label ="Sub category" + val = v['sub_category'][0] + each_html += get_row(label, val) + end + # description + unless v.dig('description').blank? + label ="Description" + val = v['description'][0] + each_html += get_row(label, val) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_material_type_attribute_renderer.rb b/hyrax/app/renderers/nested_material_type_attribute_renderer.rb new file mode 100644 index 00000000..fa1ad7cf --- /dev/null +++ b/hyrax/app/renderers/nested_material_type_attribute_renderer.rb @@ -0,0 +1,34 @@ +class NestedMaterialTypeAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + # material_type + unless v.dig('material_type').blank? + label ="Material type" + val = v['material_type'][0] + html += get_row(label, val) + end + # material_sub_type + unless v.dig('material_sub_type').blank? + label ="Material sub type" + val = v['material_sub_type'][0] + html += get_row(label, val) + end + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + # description + unless v.dig('description').blank? + label ="Description" + val = v['description'][0] + html += get_row(label, val) + end + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_organization_attribute_renderer.rb b/hyrax/app/renderers/nested_organization_attribute_renderer.rb new file mode 100644 index 00000000..6680ed1d --- /dev/null +++ b/hyrax/app/renderers/nested_organization_attribute_renderer.rb @@ -0,0 +1,33 @@ +class NestedOrganizationAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + if v.dig('organization').present? and v['organization'][0].present? + label = "Organization" + val = link_to(ERB::Util.h(v['organization'][0]), search_path(v['organization'][0])) + each_html += get_row(label, val) + end + unless v.dig('sub_organization').blank? + label = 'Sub organization' + val = v['sub_organization'][0] + each_html += get_row(label, val) + end + unless v.dig('purpose').blank? + label = 'Role' + val = v['purpose'][0] + each_html += get_row(label, val) + end + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_person_attribute_renderer.rb b/hyrax/app/renderers/nested_person_attribute_renderer.rb new file mode 100644 index 00000000..5f4bcff9 --- /dev/null +++ b/hyrax/app/renderers/nested_person_attribute_renderer.rb @@ -0,0 +1,53 @@ +class NestedPersonAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # creator name + if v.dig('name').present? and v['name'][0].present? + label = "Name" + val = link_to(ERB::Util.h(v['name'][0]), search_path(v['name'][0])) + each_html += get_row(label, val) + else + creator_name = [] + unless v.dig('first_name').blank? + creator_name = v['first_name'] + end + unless v.dig('last_name').blank? + creator_name += v['last_name'] + end + creator_name = creator_name.join(' ').strip + if creator_name.present? + label = "Name" + val = link_to(ERB::Util.h(creator_name), search_path(creator_name)) + each_html += get_row(label, val) + end + end + # complex_identifier + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + # complex_affiliation + unless v.dig('complex_affiliation').blank? + label = 'Affiliation' + renderer_class = NestedAffiliationAttributeRenderer + each_html += get_nested_output(field, label, v['complex_affiliation'], renderer_class, true) + end + # role + unless v.dig('role').blank? + label = 'Role' + val = v['role'][0] + term = RoleService.new.find_by_id(val) + val = term['label'] if term.any? + each_html += get_row(label, val) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_purchase_record_attribute_renderer.rb b/hyrax/app/renderers/nested_purchase_record_attribute_renderer.rb new file mode 100644 index 00000000..d6e6b2c6 --- /dev/null +++ b/hyrax/app/renderers/nested_purchase_record_attribute_renderer.rb @@ -0,0 +1,50 @@ +class NestedPurchaseRecordAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # title + if v.dig('title').present? and v['title'][0].present? + label ="Title" + # call search_catalog_path directly to get correct search link + val = link_to(ERB::Util.h(v['title'][0]), + Rails.application.routes.url_helpers.search_catalog_path(:"f[complex_purchase_record_title_sim][]" => v['title'][0], locale: I18n.locale) + ) + each_html += get_row(label, val) + end + # date + unless v.dig('date').blank? + each_html += get_row('Date', v['date'][0]) + end + # complex identifier + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + # supplier + unless v.dig('supplier').blank? + label = 'Supplier' + renderer_class = NestedOrganizationAttributeRenderer + each_html += get_nested_output(field, label, v['supplier'], renderer_class, true) + end + # manufacturer + unless v.dig('manufacturer').blank? + label = 'Manufacturer' + renderer_class = NestedOrganizationAttributeRenderer + each_html += get_nested_output(field, label, v['manufacturer'], renderer_class, true) + end + # purchase_record_item + unless v.dig('purchase_record_item').blank? + label = 'Purchase record item' + val = v['purchase_record_item'][0] + each_html += get_row(label, val) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_relation_attribute_renderer.rb b/hyrax/app/renderers/nested_relation_attribute_renderer.rb new file mode 100644 index 00000000..3b10df0d --- /dev/null +++ b/hyrax/app/renderers/nested_relation_attribute_renderer.rb @@ -0,0 +1,36 @@ +class NestedRelationAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # title with url + title = '' + unless v.dig('title').blank? + title = v['title'][0] + end + unless v.dig('url').blank? + link = link_to(title, v['url'][0], target: :_blank) + title = " #{link}" + end + each_html += get_row('Title', title) + # complex identifier + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + # Relationship + unless v.dig('relationship').blank? + val = v['relationship'][0] + term = RelationshipService.new.find_by_id(val) + val = term['label'] if term.any? + each_html += get_row('Relationship', val) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_rights_attribute_renderer.rb b/hyrax/app/renderers/nested_rights_attribute_renderer.rb new file mode 100644 index 00000000..6e73a6a7 --- /dev/null +++ b/hyrax/app/renderers/nested_rights_attribute_renderer.rb @@ -0,0 +1,19 @@ +class NestedRightsAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # Rights + val = v.fetch('rights', []) + each_html += get_row('Rights', val[0]) unless val.blank? + # start date + val = v.fetch('date', []) + each_html += get_row('Date', val[0]) unless val.blank? + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_source_attribute_renderer.rb b/hyrax/app/renderers/nested_source_attribute_renderer.rb new file mode 100644 index 00000000..985546d8 --- /dev/null +++ b/hyrax/app/renderers/nested_source_attribute_renderer.rb @@ -0,0 +1,64 @@ +class NestedSourceAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # title + if v.dig('title').present? and v['title'][0].present? + label = "Title" + val = link_to(ERB::Util.h(v['title'][0]), search_path(v['title'][0])) + each_html += get_row(label, val) + end + unless v.dig('alternative_title').blank? + label = 'Alternative title' + val = v['alternative_title'][0] + each_html += get_row(label, val) + end + unless v.dig('complex_person').blank? + label = 'Contributor' + renderer_class = NestedPersonAttributeRenderer + each_html += get_nested_output(field, label, v['complex_person'], renderer_class, true) + end + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + unless v.dig('issue').blank? + label = 'Issue' + val = v['issue'][0] + each_html += get_row(label, val) + end + unless v.dig('volume').blank? + label = 'Volume' + val = v['volume'][0] + each_html += get_row(label, val) + end + unless v.dig('sequence_number').blank? + label = 'Sequence number' + val = v['sequence_number'][0] + each_html += get_row(label, val) + end + unless v.dig('start_page').blank? + label = 'Start page' + val = v['start_page'][0] + each_html += get_row(label, val) + end + unless v.dig('end_page').blank? + label = 'End page' + val = v['end_page'][0] + each_html += get_row(label, val) + end + unless v.dig('total_number_of_pages').blank? + label = 'Total number of pages' + val = v['total_number_of_pages'][0] + each_html += get_row(label, val) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_specimen_type_attribute_renderer.rb b/hyrax/app/renderers/nested_specimen_type_attribute_renderer.rb new file mode 100644 index 00000000..0571b56f --- /dev/null +++ b/hyrax/app/renderers/nested_specimen_type_attribute_renderer.rb @@ -0,0 +1,73 @@ +class NestedSpecimenTypeAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # title + unless v.dig('title').blank? + label = 'Title' + val = v['title'][0] + each_html += get_row(label, val) + end + # complex_chemical_composition + unless v.dig('complex_chemical_composition').blank? + label = 'Chemical composition' + renderer_class = NestedDescIdAttributeRenderer + each_html += get_nested_output(field, label, v['complex_chemical_composition'], renderer_class, true) + end + # complex_crystallographic_structure + unless v.dig('complex_crystallographic_structure').blank? + label = 'Crystallographic structure' + renderer_class = NestedDescIdAttributeRenderer + each_html += get_nested_output(field, label, v['complex_crystallographic_structure'], renderer_class, true) + end + # description + unless v.dig('description').blank? + label = 'Description' + val = v['description'][0] + each_html += get_row(label, val) + end + # identifier + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + # complex_material_type + unless v.dig('complex_material_type').blank? + label = 'Material type' + renderer_class = NestedMaterialTypeAttributeRenderer + each_html += get_nested_output(field, label, v['complex_material_type'], renderer_class, true) + end + # complex_purchase_record + unless v.dig('complex_purchase_record').blank? + label = 'Purchase record' + renderer_class = NestedPurchaseRecordAttributeRenderer + each_html += get_nested_output(field, label, v['complex_purchase_record'], renderer_class, true) + end + # complex_shape + unless v.dig('complex_shape').blank? + label = 'Shape' + renderer_class = NestedDescIdAttributeRenderer + each_html += get_nested_output(field, label, v['complex_shape'], renderer_class, true) + end + # complex_state_of_matter + unless v.dig('complex_state_of_matter').blank? + label = 'State of matter' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_state_of_matter'], renderer_class, true) + end + # complex_structural_feature + unless v.dig('complex_structural_feature').blank? + label = 'Structural feature' + renderer_class = NestedStructuralFeatureAttributeRenderer + each_html += get_nested_output(field, label, v['complex_structural_feature'], renderer_class, true) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_structural_feature_attribute_renderer.rb b/hyrax/app/renderers/nested_structural_feature_attribute_renderer.rb new file mode 100644 index 00000000..e55ee92c --- /dev/null +++ b/hyrax/app/renderers/nested_structural_feature_attribute_renderer.rb @@ -0,0 +1,37 @@ +class NestedStructuralFeatureAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # category + unless v.dig('category').blank? + label = 'Category' + val = v['category'][0] + each_html += get_row(label, val) + end + # sub_category + unless v.dig('sub_category').blank? + label = 'Sub category' + val = v['sub_category'][0] + each_html += get_row(label, val) + end + # description + unless v.dig('description').blank? + label = 'Description' + val = v['description'][0] + each_html += get_row(label, val) + end + # identifier + unless v.dig('complex_identifier').blank? + label = 'Identifier' + renderer_class = NestedIdentifierAttributeRenderer + each_html += get_nested_output(field, label, v['complex_identifier'], renderer_class, false) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/renderers/nested_version_attribute_renderer.rb b/hyrax/app/renderers/nested_version_attribute_renderer.rb new file mode 100644 index 00000000..41e0f59e --- /dev/null +++ b/hyrax/app/renderers/nested_version_attribute_renderer.rb @@ -0,0 +1,29 @@ +class NestedVersionAttributeRenderer < NestedAttributeRenderer + def attribute_value_to_html(input_value) + html = '' + return html if input_value.blank? + value = parse_value(input_value) + value.each do |v| + each_html = '' + # version + unless v.dig('version').blank? + label = 'Version' + val = v['version'][0] + each_html += get_row(label, val) + end + unless v.dig('description').blank? + label = 'Description' + val = v['description'][0] + each_html += get_row(label, val) + end + unless v.dig('date').blank? + label = 'Date' + val = Date.parse(v['date'][0]).to_formatted_s(:standard) + each_html += get_row(label, val) + end + html += get_inner_html(each_html) + end + html_out = get_ouput_html(html) + %(#{html_out}) + end +end diff --git a/hyrax/app/services/add_identifier_service.rb b/hyrax/app/services/add_identifier_service.rb new file mode 100644 index 00000000..3eca62ea --- /dev/null +++ b/hyrax/app/services/add_identifier_service.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +class AddIdentifierService + attr_reader :dataset, :person, :user + + def initialize(dataset_id: , user_id: , complex_person_id: nil, complex_person_name: nil) + raise StandardError 'complex_person_id or complex_person_name must be specified' if complex_person_id.nil? && complex_person_name.nil? + + @dataset = Dataset.find(dataset_id) + if complex_person_id.present? + @person = dataset.complex_person.select { |p| p.id == complex_person_id }.first + elsif complex_person_name.present? + @person = dataset.complex_person.select { |p| p.name.include?(complex_person_name) }.first + end + raise StandardError 'complex_person could not be found' if person.nil? + + @user = User.find(user_id) + end + + def add_identifier(identifier_type:, identifier_value:) + raise StandardError 'invalid identifier_type' unless valid_type?(identifier_type) + + valid_type? + attr = clean_attributes + + attr[:complex_person_attributes][0][:complex_identifier_attributes] = [ + complex_identifier_attributes(identifier_type, identifier_value) + ] + + env = Hyrax::Actors::Environment.new(dataset, user.ability, attr) + Hyrax::CurationConcern.actor.update(env) + dataset.reload + end + + def clean_attributes + attributes.delete('complex_identifier') + attributes.delete('complex_affiliation') + { complex_person_attributes: [attributes] } + end + + def attributes + @attributes ||= person.attributes + end + + def complex_identifier_attributes(identifier_type, identifier_value) + { + identifier: [identifier_value], + scheme: [identifier_type] + } + end + + # def deleted_complex_identifier_attributes(identifier_type) + # existing_identifier = person.complex_identifier.select { |i| i.scheme == [identifier_type] }.first + # return {} if existing_identifier.blank? + # { + # id: existing_identifier.id, + # '_destroy' => '1' + # } + # end + + def valid_type?(identifier_type) + true if IdentifierService.new.select_active_options.map(&:last).include?(identifier_type) + end +end diff --git a/hyrax/app/services/analysis_field_service.rb b/hyrax/app/services/analysis_field_service.rb new file mode 100644 index 00000000..de320ad2 --- /dev/null +++ b/hyrax/app/services/analysis_field_service.rb @@ -0,0 +1,7 @@ +# Provide select options for analysis fields +class AnalysisFieldService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('analysis_fields') + end +end + diff --git a/hyrax/app/services/characterization_method_service.rb b/hyrax/app/services/characterization_method_service.rb new file mode 100644 index 00000000..2d0788c1 --- /dev/null +++ b/hyrax/app/services/characterization_method_service.rb @@ -0,0 +1,6 @@ +# Provide select options for characterization methods +class CharacterizationMethodService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('characterization_methods') + end +end diff --git a/hyrax/app/services/computational_method_service.rb b/hyrax/app/services/computational_method_service.rb new file mode 100644 index 00000000..f6c5a868 --- /dev/null +++ b/hyrax/app/services/computational_method_service.rb @@ -0,0 +1,6 @@ +# Provide select options for computational methods +class ComputationalMethodService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('computational_methods') + end +end diff --git a/hyrax/app/services/data_origin_service.rb b/hyrax/app/services/data_origin_service.rb new file mode 100644 index 00000000..96c37003 --- /dev/null +++ b/hyrax/app/services/data_origin_service.rb @@ -0,0 +1,6 @@ +# Provide select options for data origin +class DataOriginService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('data_origin') + end +end diff --git a/hyrax/app/services/date_service.rb b/hyrax/app/services/date_service.rb new file mode 100644 index 00000000..415253a3 --- /dev/null +++ b/hyrax/app/services/date_service.rb @@ -0,0 +1,6 @@ +# Provide select options for dates +class DateService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('dates') + end +end diff --git a/hyrax/app/services/hyrax/analytics.rb b/hyrax/app/services/hyrax/analytics.rb new file mode 100644 index 00000000..5b286588 --- /dev/null +++ b/hyrax/app/services/hyrax/analytics.rb @@ -0,0 +1,91 @@ +require 'oauth2' +require 'signet/oauth_2/client' + +# overriden to fix bug in extracting env vars - do remove once the fix is accepted into Hyrax +# see https://github.com/samvera/hyrax/pull/3934 + +module Hyrax + module Analytics + # Loads configuration options from config/analytics.yml. Expected structure: + # `analytics:` + # ` app_name: <%= ENV['GOOGLE_OAUTH_APP_NAME']` + # ` app_version: <%= ENV['GOOGLE_OAUTH_APP_VERSION']` + # ` privkey_path: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_PATH']` + # ` privkey_secret: <%= ENV['GOOGLE_OAUTH_PRIVATE_KEY_SECRET']` + # ` client_email: <%= ENV['GOOGLE_OAUTH_CLIENT_EMAIL']` + # @return [Config] + def self.config + @config ||= Config.load_from_yaml + end + private_class_method :config + + class Config + def self.load_from_yaml + filename = Rails.root.join('config', 'analytics.yml') + yaml = YAML.safe_load(ERB.new(File.read(filename)).result) + unless yaml + Rails.logger.error("Unable to fetch any keys from #{filename}.") + return new({}) + end + new yaml.fetch('analytics') + end + + REQUIRED_KEYS = %w[app_name app_version privkey_path privkey_secret client_email].freeze + + def initialize(config) + @config = config + end + + # @return [Boolean] are all the required values present? + def valid? + config_keys = @config.keys + REQUIRED_KEYS.all? { |required| config_keys.include?(required) } + end + + REQUIRED_KEYS.each do |key| + class_eval %{ def #{key}; @config.fetch('#{key}'); end } + end + end + + # Generate an OAuth2 token for Google Analytics + # @return [OAuth2::AccessToken] An OAuth2 access token for GA + def self.token(scope = 'https://www.googleapis.com/auth/analytics.readonly') + access_token = auth_client(scope).fetch_access_token! + OAuth2::AccessToken.new(oauth_client, access_token['access_token'], expires_in: access_token['expires_in']) + end + + def self.oauth_client + OAuth2::Client.new('', '', authorize_url: 'https://accounts.google.com/o/oauth2/auth', + token_url: 'https://accounts.google.com/o/oauth2/token') + end + + def self.auth_client(scope) + raise "Private key file for Google analytics was expected at '#{config.privkey_path}', but no file was found." unless File.exist?(config.privkey_path) + private_key = File.read(config.privkey_path) + Signet::OAuth2::Client.new token_credential_uri: 'https://accounts.google.com/o/oauth2/token', + audience: 'https://accounts.google.com/o/oauth2/token', + scope: scope, + issuer: config.client_email, + signing_key: OpenSSL::PKCS12.new(private_key, config.privkey_secret).key, + sub: config.client_email + end + + private_class_method :token + + # Return a user object linked to a Google Analytics account + # @return [Legato::User] A user account wit GA access + def self.user + Legato::User.new(token) + end + private_class_method :user + + # Return a Google Analytics profile matching specified ID + # @ return [Legato::Management::Profile] A user profile associated with GA + def self.profile + return unless config.valid? + user.profiles.detect do |profile| + profile.web_property_id == Hyrax.config.google_analytics_id + end + end + end +end diff --git a/hyrax/app/services/identifier_service.rb b/hyrax/app/services/identifier_service.rb new file mode 100644 index 00000000..2c813d44 --- /dev/null +++ b/hyrax/app/services/identifier_service.rb @@ -0,0 +1,7 @@ +# Provide select options for analysis fields +class IdentifierService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('identifiers') + end +end + diff --git a/hyrax/app/services/material_type_service.rb b/hyrax/app/services/material_type_service.rb new file mode 100644 index 00000000..e606c772 --- /dev/null +++ b/hyrax/app/services/material_type_service.rb @@ -0,0 +1,6 @@ +# Provide select options for material types +class MaterialTypeService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('material_types') + end +end diff --git a/hyrax/app/services/measurement_environment_service.rb b/hyrax/app/services/measurement_environment_service.rb new file mode 100644 index 00000000..8f103862 --- /dev/null +++ b/hyrax/app/services/measurement_environment_service.rb @@ -0,0 +1,6 @@ +# Provide select options for measurement environments +class MeasurementEnvironmentService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('measurement_environments') + end +end diff --git a/hyrax/app/services/processing_environment_service.rb b/hyrax/app/services/processing_environment_service.rb new file mode 100644 index 00000000..0e6eb3d2 --- /dev/null +++ b/hyrax/app/services/processing_environment_service.rb @@ -0,0 +1,6 @@ +# Provide select options for processing environments +class ProcessingEnvironmentService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('processing_environments') + end +end diff --git a/hyrax/app/services/properties_addressed_service.rb b/hyrax/app/services/properties_addressed_service.rb new file mode 100644 index 00000000..ac436b17 --- /dev/null +++ b/hyrax/app/services/properties_addressed_service.rb @@ -0,0 +1,6 @@ +# Provide select options for data origin +class PropertiesAddressedService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('properties_addressed') + end +end diff --git a/hyrax/app/services/qa_select_service_extended.rb b/hyrax/app/services/qa_select_service_extended.rb new file mode 100644 index 00000000..ee9e47b1 --- /dev/null +++ b/hyrax/app/services/qa_select_service_extended.rb @@ -0,0 +1,28 @@ +class QaSelectServiceExtended < Hyrax::QaSelectService + def find_by_id_or_label(term, &block) + a = authority.all.select { |e| (e[:label] == term || e[:id] == term) && e[:active] == true } + if a.any? + a.first + else + {} + end + end + + def find_by_id(term, &block) + a = authority.all.select { |e| e[:id] == term && e[:active] == true } + if a.any? + a.first + else + {} + end + end + + def find_by_label(term, &block) + a = authority.all.select { |e| e[:label] == term && e[:active] == true } + if a.any? + a.first + else + {} + end + end +end diff --git a/hyrax/app/services/relationship_service.rb b/hyrax/app/services/relationship_service.rb new file mode 100644 index 00000000..32b3876c --- /dev/null +++ b/hyrax/app/services/relationship_service.rb @@ -0,0 +1,6 @@ +# Provide select options for roles +class RelationshipService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('relationships') + end +end diff --git a/hyrax/app/services/rights_service.rb b/hyrax/app/services/rights_service.rb new file mode 100644 index 00000000..9d85a3ca --- /dev/null +++ b/hyrax/app/services/rights_service.rb @@ -0,0 +1,6 @@ +# Provide select options for analysis fields +class RightsService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('licenses') + end +end diff --git a/hyrax/app/services/rights_statement_service.rb b/hyrax/app/services/rights_statement_service.rb new file mode 100644 index 00000000..a601c760 --- /dev/null +++ b/hyrax/app/services/rights_statement_service.rb @@ -0,0 +1,6 @@ +# Provide select options for analysis fields +class RightsStatementService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('rights_statements') + end +end diff --git a/hyrax/app/services/role_service.rb b/hyrax/app/services/role_service.rb new file mode 100644 index 00000000..d9994a90 --- /dev/null +++ b/hyrax/app/services/role_service.rb @@ -0,0 +1,6 @@ +# Provide select options for roles +class RoleService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('roles') + end +end diff --git a/hyrax/app/services/structural_feature_service.rb b/hyrax/app/services/structural_feature_service.rb new file mode 100644 index 00000000..f4bc3376 --- /dev/null +++ b/hyrax/app/services/structural_feature_service.rb @@ -0,0 +1,6 @@ +# Provide select options for structural features +class StructuralFeatureService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('structural_features') + end +end diff --git a/hyrax/app/services/synthesis_and_processing_service.rb b/hyrax/app/services/synthesis_and_processing_service.rb new file mode 100644 index 00000000..cf84a299 --- /dev/null +++ b/hyrax/app/services/synthesis_and_processing_service.rb @@ -0,0 +1,6 @@ +# Provide select options for synthesis and processing +class SynthesisAndProcessingService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('synthesis_and_processing') + end +end diff --git a/hyrax/app/services/user_authorisation_service.rb b/hyrax/app/services/user_authorisation_service.rb new file mode 100644 index 00000000..f32a8ef8 --- /dev/null +++ b/hyrax/app/services/user_authorisation_service.rb @@ -0,0 +1,42 @@ +require 'net/ldap' +class UserAuthorisationService + # This service is called immediately after authentication (see config/initializers/devise.rb). It updates the user's + # authorisation attributes from an LDAP source (USER_AUTHORISATION_LDAP_HOST). This is necessary as the CAS server + # does not provide employeeType/email etc. + # NB: In the future, this service may query a TSV file on a network drive rather than an LDAP server. + + def initialize(user) + @user = user + end + + def enabled? + ENV['USER_AUTHORISATION_LDAP_HOST'].present? && + ENV['USER_AUTHORISATION_LDAP_BASE'].present? && + ENV['USER_AUTHORISATION_LDAP_ATTRIBUTE'].present? + end + + def update_attributes + success = false + if enabled? && records.length == 1 + records.first.tap do |record| + @user.update(email: record[:mail]&.first, + display_name: record[:cn]&.first, + employee_type_code: record[:employeeType]&.first&.first) + success = true + end + else + puts "WARNING: UserAuthorisationService failed to retrieve user attributes, check USER_AUTHORISATION_LDAP_HOST, USER_AUTHORISATION_LDAP_BASE, USER_AUTHORISATION_LDAP_ATTRIBUTE env vars" + end + success + end + + private + + def server + @server ||= Net::LDAP.new(host: ENV['USER_AUTHORISATION_LDAP_HOST'], port: ENV.fetch('USER_AUTHORISATION_LDAP_PORT', 389)) + end + + def records + @records ||= server.search(base: ENV['USER_AUTHORISATION_LDAP_BASE'], filter: Net::LDAP::Filter.eq(ENV['USER_AUTHORISATION_LDAP_ATTRIBUTE'], @user.username)) + end +end diff --git a/hyrax/app/services/willow_sword/crosswalk_from_mdr.rb b/hyrax/app/services/willow_sword/crosswalk_from_mdr.rb new file mode 100644 index 00000000..a7077b3c --- /dev/null +++ b/hyrax/app/services/willow_sword/crosswalk_from_mdr.rb @@ -0,0 +1,50 @@ +require 'importers/dataset_importer/parse_xml' +module WillowSword + class CrosswalkFromMdr + attr_reader :metadata, :model, :mapped_metadata, :files_metadata, :errors + + include Importers::DatasetImporter::ParseXml + + def initialize(src_file, headers) + @metadata_file = src_file + @import_dir = File.dirname(@metadata_file) + @headers = headers + @model = nil + @metadata = {} + @attributes = {} + @errors = [] + @mapped_metadata = {} + # contains a hash with the keys filename, filetype, filepath, metadata + @files_metadata = [] + end + + def map_xml + return unless @metadata_file.present? + return unless File.exist? @metadata_file + parse_metadata + puts @attributes + puts '-'*70 + @metadata = @attributes + @mapped_metadata = @attributes + get_files + puts @mapped_metadata + end + + def get_files + all_files = Dir.glob(File.join(@import_dir, '*')) + all_files.each do |file| + # 1. List of files does not include metadata file + # 2. Directories are ignored from list of files + # 3. @files is an array of hashes, with each hash containing + # filename, filetype, filepath, metadata + next if file == @metadata_file + next if File.directory?(file) + @files_metadata << { + 'filename' => File.basename(file), + 'filepath' => file + } + end + end + + end +end diff --git a/hyrax/app/views/_logo.html.erb b/hyrax/app/views/_logo.html.erb new file mode 100644 index 00000000..f3515c6e --- /dev/null +++ b/hyrax/app/views/_logo.html.erb @@ -0,0 +1,3 @@ + diff --git a/hyrax/app/views/_masthead.html.erb b/hyrax/app/views/_masthead.html.erb new file mode 100644 index 00000000..1614b29c --- /dev/null +++ b/hyrax/app/views/_masthead.html.erb @@ -0,0 +1,22 @@ +
    + + <%= render '/searchbar' %> +
    + diff --git a/hyrax/app/views/_searchbar.html.erb b/hyrax/app/views/_searchbar.html.erb new file mode 100644 index 00000000..50e7eec3 --- /dev/null +++ b/hyrax/app/views/_searchbar.html.erb @@ -0,0 +1,9 @@ + diff --git a/hyrax/app/views/_user_util_links.html.erb b/hyrax/app/views/_user_util_links.html.erb new file mode 100644 index 00000000..76ae8aad --- /dev/null +++ b/hyrax/app/views/_user_util_links.html.erb @@ -0,0 +1,38 @@ + diff --git a/hyrax/app/views/devise/confirmations/new.html.erb b/hyrax/app/views/devise/confirmations/new.html.erb new file mode 100644 index 00000000..4efa93f8 --- /dev/null +++ b/hyrax/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,16 @@ +

    Resend confirmation instructions

    + +<%= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> + <%= f.error_notification %> + <%= f.full_error :confirmation_token %> + +
    + <%= f.input :username, required: true, autofocus: true %> +
    + +
    + <%= f.button :submit, "Resend confirmation instructions" %> +
    +<% end %> + +<%= render "devise/shared/links" %> diff --git a/hyrax/app/views/devise/mailer/confirmation_instructions.html.erb b/hyrax/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 00000000..7aa85afd --- /dev/null +++ b/hyrax/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

    Welcome <%= @username %>!

    + +

    You can confirm your account through the link below:

    + +

    <%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

    diff --git a/hyrax/app/views/devise/mailer/email_changed.html.erb b/hyrax/app/views/devise/mailer/email_changed.html.erb new file mode 100644 index 00000000..32f4ba80 --- /dev/null +++ b/hyrax/app/views/devise/mailer/email_changed.html.erb @@ -0,0 +1,7 @@ +

    Hello <%= @email %>!

    + +<% if @resource.try(:unconfirmed_email?) %> +

    We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.

    +<% else %> +

    We're contacting you to notify you that your email has been changed to <%= @resource.email %>.

    +<% end %> diff --git a/hyrax/app/views/devise/mailer/password_change.html.erb b/hyrax/app/views/devise/mailer/password_change.html.erb new file mode 100644 index 00000000..60ce9784 --- /dev/null +++ b/hyrax/app/views/devise/mailer/password_change.html.erb @@ -0,0 +1,3 @@ +

    Hello <%= @resource.username %>!

    + +

    We're contacting you to notify you that your password has been changed.

    diff --git a/hyrax/app/views/devise/mailer/reset_password_instructions.html.erb b/hyrax/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 00000000..0685a211 --- /dev/null +++ b/hyrax/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

    Hello <%= @resource.username %>!

    + +

    Someone has requested a link to change your password. You can do this through the link below.

    + +

    <%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

    + +

    If you didn't request this, please ignore this email.

    +

    Your password won't change until you access the link above and create a new one.

    diff --git a/hyrax/app/views/devise/mailer/unlock_instructions.html.erb b/hyrax/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 00000000..22b07bd4 --- /dev/null +++ b/hyrax/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

    Hello <%= @resource.username %>!

    + +

    Your account has been locked due to an excessive number of unsuccessful sign in attempts.

    + +

    Click the link below to unlock your account:

    + +

    <%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

    diff --git a/hyrax/app/views/devise/passwords/edit.html.erb b/hyrax/app/views/devise/passwords/edit.html.erb new file mode 100644 index 00000000..a938930b --- /dev/null +++ b/hyrax/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,19 @@ +

    Change your password

    + +<%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> + <%= f.error_notification %> + + <%= f.input :reset_password_token, as: :hidden %> + <%= f.full_error :reset_password_token %> + +
    + <%= f.input :password, label: "New password", required: true, autofocus: true, hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length) %> + <%= f.input :password_confirmation, label: "Confirm your new password", required: true %> +
    + +
    + <%= f.button :submit, "Change my password" %> +
    +<% end %> + +<%= render "devise/shared/links" %> diff --git a/hyrax/app/views/devise/passwords/new.html.erb b/hyrax/app/views/devise/passwords/new.html.erb new file mode 100644 index 00000000..c66d76ef --- /dev/null +++ b/hyrax/app/views/devise/passwords/new.html.erb @@ -0,0 +1,15 @@ +

    Forgot your password?

    + +<%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> + <%= f.error_notification %> + +
    + <%= f.input :username, required: true, autofocus: true %> +
    + +
    + <%= f.button :submit, "Send me reset password instructions" %> +
    +<% end %> + +<%= render "devise/shared/links" %> diff --git a/hyrax/app/views/devise/registrations/edit.html.erb b/hyrax/app/views/devise/registrations/edit.html.erb new file mode 100644 index 00000000..76ab1660 --- /dev/null +++ b/hyrax/app/views/devise/registrations/edit.html.erb @@ -0,0 +1,27 @@ +

    Edit <%= resource_name.to_s.humanize %>

    + +<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> + <%= f.error_notification %> + +
    + <%= f.input :username, required: true, autofocus: true %> + + <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> +

    Currently waiting confirmation for: <%= resource.unconfirmed_email %>

    + <% end %> + + <%= f.input :password, autocomplete: "off", hint: "leave it blank if you don't want to change it", required: false %> + <%= f.input :password_confirmation, required: false %> + <%= f.input :current_password, hint: "we need your current password to confirm your changes", required: true %> +
    + +
    + <%= f.button :submit, "Update" %> +
    +<% end %> + +

    Cancel my account

    + +

    Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>

    + +<%= link_to "Back", :back %> diff --git a/hyrax/app/views/devise/registrations/new.html.erb b/hyrax/app/views/devise/registrations/new.html.erb new file mode 100644 index 00000000..41e45837 --- /dev/null +++ b/hyrax/app/views/devise/registrations/new.html.erb @@ -0,0 +1,17 @@ +

    Sign up

    + +<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> + <%= f.error_notification %> + +
    + <%= f.input :username, required: true, autofocus: true %> + <%= f.input :password, required: true, hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length) %> + <%= f.input :password_confirmation, required: true %> +
    + +
    + <%= f.button :submit, "Sign up" %> +
    +<% end %> + +<%= render "devise/shared/links" %> diff --git a/hyrax/app/views/devise/sessions/new.html.erb b/hyrax/app/views/devise/sessions/new.html.erb new file mode 100644 index 00000000..05734636 --- /dev/null +++ b/hyrax/app/views/devise/sessions/new.html.erb @@ -0,0 +1,15 @@ +

    Log in

    + +<%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> +
    + <%= f.input :username, required: false, autofocus: true %> + <%= f.input :password, required: false %> + <%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %> +
    + +
    + <%= f.button :submit, "Log in" %> +
    +<% end %> + +<%= render "devise/shared/links" %> diff --git a/hyrax/app/views/devise/shared/_links.html.erb b/hyrax/app/views/devise/shared/_links.html.erb new file mode 100644 index 00000000..e6a3e419 --- /dev/null +++ b/hyrax/app/views/devise/shared/_links.html.erb @@ -0,0 +1,25 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Log in", new_session_path(resource_name) %>
    +<% end -%> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
    +<% end -%> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
    +<% end -%> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
    +<% end -%> + +<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
    +<% end -%> + +<%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> + <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %>
    + <% end -%> +<% end -%> diff --git a/hyrax/app/views/devise/unlocks/new.html.erb b/hyrax/app/views/devise/unlocks/new.html.erb new file mode 100644 index 00000000..8450c59f --- /dev/null +++ b/hyrax/app/views/devise/unlocks/new.html.erb @@ -0,0 +1,16 @@ +

    Resend unlock instructions

    + +<%= simple_form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> + <%= f.error_notification %> + <%= f.full_error :unlock_token %> + +
    + <%= f.input :username, required: true, autofocus: true %> +
    + +
    + <%= f.button :submit, "Resend unlock instructions" %> +
    +<% end %> + +<%= render "devise/shared/links" %> diff --git a/hyrax/app/views/hyrax/base/_guts4form.html.erb b/hyrax/app/views/hyrax/base/_guts4form.html.erb new file mode 100644 index 00000000..80066b14 --- /dev/null +++ b/hyrax/app/views/hyrax/base/_guts4form.html.erb @@ -0,0 +1,56 @@ +<% # we will yield to content_for for each tab, e.g. :files_tab %> +<% # Override Hyrax 2.6 - remove relationships tab from here %> +<% tabs ||= %w[metadata files] # default tab order %> +
    +
    +
    + + + + +
    + <% (tabs - ['share']).each_with_index do | tab, i | %> + <% if i == 0 %> +
    + <% else %> +
    + <% end %> +
    + <% # metadata_tab is sometimes provided %> + <%= yield "#{tab}_tab".to_sym if content_for? "#{tab}_tab".to_sym %> + <%= render "form_#{tab}", f: f %> +
    +
    + <% end %> + +
    +
    + <%= render "form_share", f: f %> +
    +
    +
    +
    +
    + + +
    diff --git a/hyrax/app/views/hyrax/base/_representative_media.html.erb b/hyrax/app/views/hyrax/base/_representative_media.html.erb new file mode 100644 index 00000000..48b67405 --- /dev/null +++ b/hyrax/app/views/hyrax/base/_representative_media.html.erb @@ -0,0 +1,10 @@ +<%# Copied from Hyrax for upgraded universal viewer, @todo remove on upgrade to Hyrax 3.x %> +<% if presenter.representative_id.present? && presenter.representative_presenter.present? %> + <% if defined?(viewer) && viewer %> + <%= iiif_viewer_display presenter %> + <% else %> + <%= nims_media_display presenter.representative_presenter %> + <% end %> +<% else %> + <%= image_tag 'default.png', class: "canonical-image" %> +<% end %> diff --git a/hyrax/app/views/hyrax/base/_show_actions.html.erb b/hyrax/app/views/hyrax/base/_show_actions.html.erb new file mode 100644 index 00000000..1940d0af --- /dev/null +++ b/hyrax/app/views/hyrax/base/_show_actions.html.erb @@ -0,0 +1,50 @@ +
    + <% if Hyrax.config.analytics? %> + <%= link_to "Analytics", presenter.stats_path, id: 'stats', class: 'btn btn-default' %> + <% end %> + <% if presenter.editor? %> + <%= link_to "Edit", edit_polymorphic_path([main_app, presenter]), class: 'btn btn-default' %> + <%= link_to "Delete", [main_app, presenter], class: 'btn btn-danger', data: { confirm: "Delete this #{presenter.human_readable_type}?" }, method: :delete %> + <% if presenter.member_presenters.size > 1 %> + <%= link_to t("hyrax.file_manager.link_text"), polymorphic_path([main_app, :file_manager, presenter]), class: 'btn btn-default' %> + <% end %> + <% if presenter.valid_child_concerns.length > 0 %> +
    + + +
    + <% end %> + <% end %> + <% # Override Hyrax 2.6 - remove add to collection button %> + <% +=begin%> + <% if presenter.show_deposit_for?(collections: @user_collections) %> + + <%= button_tag t('hyrax.dashboard.my.action.add_to_collection'), + class: 'btn btn-default submits-batches submits-batches-add', + data: { toggle: "modal", target: "#collection-list-container" } %> + <% end %> +<% +=end%> + <% if presenter.work_featurable? %> + <%= link_to "Feature", hyrax.featured_work_path(presenter, format: :json), + data: { behavior: 'feature' }, + class: presenter.display_unfeature_link? ? 'btn btn-default collapse' : 'btn btn-default' %> + + <%= link_to "Unfeature", hyrax.featured_work_path(presenter, format: :json), + data: { behavior: 'unfeature' }, + class: presenter.display_feature_link? ? 'btn btn-default collapse' : 'btn btn-default' %> + <% end %> +
    + + + + + <%= render 'hyrax/dashboard/collections/form_for_select_collection', user_collections: @user_collections %> diff --git a/hyrax/app/views/hyrax/base/_work_title.erb b/hyrax/app/views/hyrax/base/_work_title.erb new file mode 100644 index 00000000..eb934c42 --- /dev/null +++ b/hyrax/app/views/hyrax/base/_work_title.erb @@ -0,0 +1,18 @@ +<% presenter.title.each_with_index do |title, index| %> +
    +
    + <% if index == 0 %> +

    <%= title %> + <%= presenter.permission_badge %> <%= presenter.workflow.badge %> +

    + <% else %> +

    <%= title %>

    + <% end %> +
    +
    + <% if index == 0 %> + <%= render "show_actions", presenter: presenter %> + <% end %> +
    +
    +<% end %> diff --git a/hyrax/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb b/hyrax/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb new file mode 100644 index 00000000..479c1f60 --- /dev/null +++ b/hyrax/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb @@ -0,0 +1,8 @@ +<%# override file ported from Hyrax master (slated for 3.x) @todo remove on upgrade to Hyrax 3.x %> +
    + +
    diff --git a/hyrax/app/views/hyrax/base/show.html.erb b/hyrax/app/views/hyrax/base/show.html.erb new file mode 100644 index 00000000..35568c85 --- /dev/null +++ b/hyrax/app/views/hyrax/base/show.html.erb @@ -0,0 +1,48 @@ +<% provide :page_title, @presenter.page_title %> + +<% render 'shared/citations' %> + +
    +
    + <%= render 'work_type', presenter: @presenter %> +
    +
     
    +
    +
    +
    + <%= render 'work_title', presenter: @presenter %> +
    +
    +
    + <%= render 'workflow_actions_widget', presenter: @presenter %> + <% if @presenter.iiif_viewer? %> +
    + <%= render 'representative_media', presenter: @presenter, viewer: true %> +
    + <% end %> +
    + <%= render 'representative_media', presenter: @presenter, viewer: false unless @presenter.iiif_viewer? %> + <%= render 'citations', presenter: @presenter %> + <%#= render 'social_media' %> +
    +
    + <%= render 'relationships', presenter: @presenter %> + + <% if can? :read_abstract, @presenter.model_name.name.constantize %> + <%= render 'work_description', presenter: @presenter %> + <% end %> + <%= render 'metadata', presenter: @presenter %> + <%= nims_media_display(@presenter.representative_presenter, datatable: true) if @presenter&.representative_presenter&.respond_to?(:csv?) && @presenter&.representative_presenter&.csv? %> +
    + +
    + <%= render 'items', presenter: @presenter %> + <%# TODO: we may consider adding these partials in the future %> + <%# = render 'sharing_with', presenter: @presenter %> + <%# = render 'user_activity', presenter: @presenter %> +
    +
    +
    +
    +
    +
    diff --git a/hyrax/app/views/hyrax/batch_uploads/_form.html.erb b/hyrax/app/views/hyrax/batch_uploads/_form.html.erb new file mode 100644 index 00000000..5aa3b86b --- /dev/null +++ b/hyrax/app/views/hyrax/batch_uploads/_form.html.erb @@ -0,0 +1,22 @@ +<%= simple_form_for [hyrax, @form], + html: { + data: { behavior: 'work-form', + 'param-key' => @form.model_name.param_key }, + multipart: true + } do |f| %> + <% provide :files_tab do %> +

    <%= t("hyrax.batch_uploads.files.instructions") %>

    +

    <%= t("hyrax.batch_uploads.files.upload_type_instructions") %> + <%= link_to t("hyrax.batch_uploads.files.button_label"), [main_app, :new, Hyrax.primary_work_type.model_name.singular_route_key] %> +

    + <% end %> + <% # Override Hyrax 2.6 - remove relationships tab from here %> + <%= render 'hyrax/base/guts4form', f: f, tabs: %w[files metadata] %> + <%= f.hidden_field :payload_concern, value: @form.payload_concern %> +<% end %> + + diff --git a/hyrax/app/views/hyrax/contact_form/new.html.erb b/hyrax/app/views/hyrax/contact_form/new.html.erb new file mode 100644 index 00000000..c9076662 --- /dev/null +++ b/hyrax/app/views/hyrax/contact_form/new.html.erb @@ -0,0 +1,50 @@ +
    + <%= render 'directions' %> +
    + +

    + <%= t('hyrax.contact_form.header') %> +

    + +<% if user_signed_in? %> + <% nm = current_user.name %> + <% em = current_user.email %> +<% else %> + <% nm = '' %> + <% em = '' %> +<% end %> + +<%= form_for @contact_form, url: hyrax.contact_form_index_path, + html: { class: 'form-horizontal' } do |f| %> + <%= f.text_field :contact_method, class: 'hide' %> +
    + <%= f.label :category, t('hyrax.contact_form.type_label'), class: "col-sm-2 control-label" %> + <% issue_types = Hyrax::ContactForm.issue_types_for_locale.dup %> + <% issue_types.unshift([t('hyrax.contact_form.select_type'), nil]) %> +
    + <%= f.select 'category', options_for_select(issue_types), {}, {class: 'form-control', required: true } %> +
    +
    + +
    + <%= f.label :name, t('hyrax.contact_form.name_label'), class: "col-sm-2 control-label" %> +
    <%= f.text_field :name, value: nm, class: 'form-control', required: true, readonly: user_signed_in? %>
    +
    + +
    + <%= f.label :email, t('hyrax.contact_form.email_label'), class: "col-sm-2 control-label" %> +
    <%= f.text_field :email, value: em, class: 'form-control', required: true, readonly: user_signed_in? %>
    +
    + +
    + <%= f.label :subject, t('hyrax.contact_form.subject_label'), class: "col-sm-2 control-label" %> +
    <%= f.text_field :subject, class: 'form-control', required: true %>
    +
    + +
    + <%= f.label :message, t('hyrax.contact_form.message_label'), class: "col-sm-2 control-label" %> +
    <%= f.text_area :message, rows: 4, class: 'form-control', required: true %>
    +
    + + <%= f.submit value: t('hyrax.contact_form.button_label'), class: "btn btn-primary" %> +<% end %> diff --git a/hyrax/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb b/hyrax/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb new file mode 100644 index 00000000..fcf7df0e --- /dev/null +++ b/hyrax/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb @@ -0,0 +1,14 @@ +
  • <%= t('hyrax.admin.sidebar.repository_objects') %>
  • + + <% # Override Hyrax 2.6 - restrict collections to admins %> + <% if can? :read, :admin_dashboard %> + <%= menu.nav_link(hyrax.my_collections_path, + also_active_for: hyrax.dashboard_collections_path) do %> + <%= t('hyrax.admin.sidebar.collections') %> + <% end %> + <% end %> + + <%= menu.nav_link(hyrax.my_works_path, + also_active_for: hyrax.dashboard_works_path) do %> + <%= t('hyrax.admin.sidebar.works') %> + <% end %> \ No newline at end of file diff --git a/hyrax/app/views/hyrax/datasets/_attribute_rows.html.erb b/hyrax/app/views/hyrax/datasets/_attribute_rows.html.erb new file mode 100644 index 00000000..9a1f3e18 --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_attribute_rows.html.erb @@ -0,0 +1,143 @@ + +
    + + +
    + +
    +

    + Description +

    +
    + +
    +
    + <% if can? :read_alternative_title, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:alternative_title, label: t('ngdr.fields.alternative_title'), html_dl: true) %> + <% end %> + + + + <% if can? :read_creator, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_person, render_as: :nested_person, label: t('ngdr.fields.complex_person'), html_dl: true) %> + <% end %> + + <% if can? :read_organization, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_organization, render_as: :nested_organization, label: t('ngdr.fields.complex_organization'), html_dl: true) %> + <% end %> + + <% if can? :read_keyword, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %> + <% end %> + + <% if can? :read_subject, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %> + <% end %> + + <% if can? :read_language, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:language, render_as: :faceted, html_dl: true) %> + <% end %> + + <% if can? :read_publisher, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:publisher, render_as: :faceted, html_dl: true) %> + <% end %> + + <% if can? :read_date, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_date, render_as: :nested_date, label: t('ngdr.fields.complex_date'), html_dl: true) %> + <% end %> + + <% if can? :read_identifier, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_identifier, render_as: :nested_identifier, label: t('ngdr.fields.complex_identifier'), html_dl: true) %> + <% end %> + + + <%= presenter.attribute_to_html(:license, render_as: :license, html_dl: true) %> + + <% if can? :read_rights, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_rights, render_as: :nested_rights, label: t('ngdr.fields.complex_rights'), html_dl: true) %> + <%#= # presenter.attribute_to_html(:rights_statement, render_as: :rights_statement, html_dl: true) %> + <%#= # presenter.attribute_to_html(:rights_notes, html_dl: true) %> + <% end %> + + <% if can? :read_version, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_version, render_as: :nested_version, label: t('ngdr.fields.complex_version'), html_dl: true) %> + <% end %> + + <% if can? :read_resource_type, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:resource_type, render_as: :faceted, html_dl: true) %> + <% end %> + + <% if can? :read_related, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_relation, render_as: :nested_relation, label: t('ngdr.fields.complex_relation'), html_dl: true) %> + <% end %> + + <% if can? :read_source, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:source, html_dl: true) %> + <% end %> + + <%= presenter.attribute_to_html(:custom_property, render_as: :nested_custom_property, label: t('ngdr.fields.custom_property'), html_dl: true) %> + + + <%= presenter.attribute_to_html(:date_created, render_as: :linked, search_field: 'date_created_tesim', html_dl: true) %> + <%= presenter.attribute_to_html(:date_modified, label: t('hyrax.base.show.last_modified'), html_dl: true) %> + <%= presenter.attribute_to_html(:access_right, html_dl: true) %> +
    +
    +
    + + +
    + +
    +

    + Method +

    +
    + +
    +
    + <%= presenter.attribute_to_html(:characterization_methods, render_as: :faceted, label: t('ngdr.fields.characterization_methods'), html_dl: true) %> + <%= presenter.attribute_to_html(:computational_methods, render_as: :faceted, label: t('ngdr.fields.computational_methods'), html_dl: true) %> + <%= presenter.attribute_to_html(:data_origin, render_as: :faceted, label: t('ngdr.fields.data_origin'), html_dl: true) %> + <%= presenter.attribute_to_html(:origin_system_provenance, label: t('ngdr.fields.origin_system_provenance'), html_dl: true) %> + <%= presenter.attribute_to_html(:properties_addressed, render_as: :faceted, label: t('ngdr.fields.properties_addressed'), html_dl: true) %> + <%= presenter.attribute_to_html(:specimen_set, label: t('ngdr.fields.specimen_set'), html_dl: true) %> + <%= presenter.attribute_to_html(:synthesis_and_processing, render_as: :faceted, label: t('ngdr.fields.synthesis_and_processing'), html_dl: true) %> +
    +
    +
    + + +
    + +
    +

    + Instruments +

    +
    + +
    +
    + <%= presenter.attribute_to_html(:complex_instrument, render_as: :nested_instrument, label: t('ngdr.fields.instrument'), html_dl: true) %> +
    +
    +
    + + +
    + + + +
    +
    + <%= presenter.attribute_to_html(:complex_specimen_type, render_as: :nested_specimen_type, label: t('ngdr.fields.complex_specimen_type'), html_dl: true) %> +
    +
    +
    + +
    + diff --git a/hyrax/app/views/hyrax/datasets/_dataset.html.erb b/hyrax/app/views/hyrax/datasets/_dataset.html.erb new file mode 100644 index 00000000..074a62e9 --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_dataset.html.erb @@ -0,0 +1,2 @@ +<%# This is a search result view %> +<%= render 'catalog/document', document: dataset, document_counter: dataset_counter %> diff --git a/hyrax/app/views/hyrax/datasets/_form.html.erb b/hyrax/app/views/hyrax/datasets/_form.html.erb new file mode 100644 index 00000000..81774af3 --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_form.html.erb @@ -0,0 +1,31 @@ +<%= simple_form_for [main_app, @form], + html: { + data: { behavior: 'work-form', + 'param-key' => @form.model_name.param_key }, + multipart: true + } do |f| %> + <% if f.object.errors.any? %> + + <% end %> + <% if Flipflop.batch_upload? && f.object.new_record? %> + <% provide :metadata_tab do %> +

    To create a separate work for each of the files, go to <%= link_to "Batch upload", hyrax.new_batch_upload_path %>

    + <% end %> + <% end %> + <%= render 'hyrax/datasets/guts4form', f: f %> +<% end %> + + diff --git a/hyrax/app/views/hyrax/datasets/_form_instrument.html.erb b/hyrax/app/views/hyrax/datasets/_form_instrument.html.erb new file mode 100644 index 00000000..ad6fcccd --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_form_instrument.html.erb @@ -0,0 +1,5 @@ +
    + <% f.object.instrument_tab_terms.each do |term| %> + <%= render_edit_field_partial(term, f: f) %> + <% end %> +
    diff --git a/hyrax/app/views/hyrax/datasets/_form_metadata.html.erb b/hyrax/app/views/hyrax/datasets/_form_metadata.html.erb new file mode 100644 index 00000000..57bce28a --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_form_metadata.html.erb @@ -0,0 +1,6 @@ +
    + <% f.object.metadata_tab_terms.each do |term| %> + <%= render_edit_field_partial(term, f: f) %> + <% end %> + <%= render 'form_media', f: f %> +
    diff --git a/hyrax/app/views/hyrax/datasets/_form_method.html.erb b/hyrax/app/views/hyrax/datasets/_form_method.html.erb new file mode 100644 index 00000000..bed5d6cf --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_form_method.html.erb @@ -0,0 +1,5 @@ +
    + <% f.object.method_tab_terms.each do |term| %> + <%= render_edit_field_partial(term, f: f) %> + <% end %> +
    diff --git a/hyrax/app/views/hyrax/datasets/_form_specimen.html.erb b/hyrax/app/views/hyrax/datasets/_form_specimen.html.erb new file mode 100644 index 00000000..082cdb8c --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_form_specimen.html.erb @@ -0,0 +1,5 @@ +
    + <% f.object.specimen_tab_terms.each do |term| %> + <%= render_edit_field_partial(term, f: f) %> + <% end %> +
    diff --git a/hyrax/app/views/hyrax/datasets/_guts4form.html.erb b/hyrax/app/views/hyrax/datasets/_guts4form.html.erb new file mode 100644 index 00000000..73fc103a --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_guts4form.html.erb @@ -0,0 +1,56 @@ +<% # we will yield to content_for for each tab, e.g. :files_tab %> +<% # Override Hyrax 2.6 - remove relationships tab from here %> +<% tabs ||= %w[metadata method instrument specimen files] # default tab order %> +
    +
    +
    + + + + +
    + <% (tabs - ['share']).each_with_index do | tab, i | %> + <% if i == 0 %> +
    + <% else %> +
    + <% end %> +
    + <% # metadata_tab is sometimes provided %> + <%= yield "#{tab}_tab".to_sym if content_for? "#{tab}_tab".to_sym %> + <%= render "form_#{tab}", f: f %> +
    +
    + <% end %> + +
    +
    + <%= render "form_share", f: f %> +
    +
    +
    +
    +
    + + +
    diff --git a/hyrax/app/views/hyrax/file_sets/_show_actions.html.erb b/hyrax/app/views/hyrax/file_sets/_show_actions.html.erb new file mode 100644 index 00000000..3a6703ae --- /dev/null +++ b/hyrax/app/views/hyrax/file_sets/_show_actions.html.erb @@ -0,0 +1,15 @@ +
    + <% if Hyrax.config.analytics? %> + <%= link_to "Analytics", @presenter.stats_path, id: 'stats', class: 'btn btn-default' %> + <% end %> + + <% if @presenter.editor? %> + <%= link_to "Edit This #{@presenter.human_readable_type}", edit_polymorphic_path([main_app, @presenter]), + class: 'btn btn-default' %> + <%= link_to "Delete This #{@presenter.human_readable_type}", [main_app, @presenter], + class: 'btn btn-danger', data: { confirm: "Delete this #{@presenter.human_readable_type}?" }, + method: :delete %> + <% end %> + + <%# render 'social_media' %> +
    diff --git a/hyrax/app/views/hyrax/file_sets/media_display/_csv.html.erb b/hyrax/app/views/hyrax/file_sets/media_display/_csv.html.erb new file mode 100644 index 00000000..732ec072 --- /dev/null +++ b/hyrax/app/views/hyrax/file_sets/media_display/_csv.html.erb @@ -0,0 +1,28 @@ +<% if local_assigns[:datatable] %> +
    + + +
    +
    + +
    +
    + +
    +
    +<% else %> +
    + Preview +
    + <% if Hyrax.config.display_media_download_link? %> +
    + <%= link_to t('hyrax.file_set.show.download'), hyrax.download_path(file_set.id), id: "file_download", data: { label: file_set.id }, target: "_new" %> +
    + <% end %> +<% end %> diff --git a/hyrax/app/views/hyrax/file_sets/show.html.erb b/hyrax/app/views/hyrax/file_sets/show.html.erb new file mode 100644 index 00000000..c93941f3 --- /dev/null +++ b/hyrax/app/views/hyrax/file_sets/show.html.erb @@ -0,0 +1,21 @@ +<% provide :page_title, @presenter.page_title %> +
    +
    +
    + <%= nims_media_display @presenter %> + <%= render 'show_actions', presenter: @presenter %> + <%= render 'single_use_links', presenter: @presenter if @presenter.editor? %> +
    +
    +
    + <%= render 'file_set_title', presenter: @presenter %> +
    + + <%# TODO: render 'show_descriptions' See https://github.com/samvera/hyrax/issues/1481 %> + <%= render 'show_details' %> + + <%= nims_media_display(@presenter, datatable: true) if @presenter.respond_to?(:csv?) && @presenter.csv? %> + <%= render 'hyrax/users/activity_log', events: @presenter.events %> +
    +
    +
    diff --git a/hyrax/app/views/hyrax/homepage/_announcement.html.erb b/hyrax/app/views/hyrax/homepage/_announcement.html.erb new file mode 100644 index 00000000..fe0c5836 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_announcement.html.erb @@ -0,0 +1,3 @@ +<% if display_content_block? @announcement_text %> + <%= displayable_content_block @announcement_text, class: 'row', id: 'announcement' %> +<% end %> diff --git a/hyrax/app/views/hyrax/homepage/_featured.html.erb b/hyrax/app/views/hyrax/homepage/_featured.html.erb new file mode 100644 index 00000000..93919ee6 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_featured.html.erb @@ -0,0 +1,4 @@ +<% presenter = featured.presenter %> +
    + <%= render 'hyrax/homepage/featured_fields', featured: presenter %> +
    diff --git a/hyrax/app/views/hyrax/homepage/_featured_fields.html.erb b/hyrax/app/views/hyrax/homepage/_featured_fields.html.erb new file mode 100644 index 00000000..d26c1966 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_featured_fields.html.erb @@ -0,0 +1,23 @@ + + + diff --git a/hyrax/app/views/hyrax/homepage/_featured_researcher.html.erb b/hyrax/app/views/hyrax/homepage/_featured_researcher.html.erb new file mode 100644 index 00000000..971bac23 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_featured_researcher.html.erb @@ -0,0 +1,16 @@ + diff --git a/hyrax/app/views/hyrax/homepage/_featured_works.html.erb b/hyrax/app/views/hyrax/homepage/_featured_works.html.erb new file mode 100644 index 00000000..a495db58 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_featured_works.html.erb @@ -0,0 +1,30 @@ + diff --git a/hyrax/app/views/hyrax/homepage/_home_browse.html.erb b/hyrax/app/views/hyrax/homepage/_home_browse.html.erb new file mode 100644 index 00000000..d7d5d2f5 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_home_browse.html.erb @@ -0,0 +1,52 @@ +
    +
    + <% + field = Solrizer.solr_name("human_readable_type", :facetable) + item = 'Publication' + path = main_app.search_catalog_path(search_state.add_facet_params_and_redirect(field, item)) + data = '' + %> +

    <%= link_to path do %> + <%= image_tag 'final-icons-01-100.png', class: "homepage-icon" %> + <% end %>

    +

    <%= link_to path, + class: 'btn btn-primary', + data: data do %> + <%= t('hyrax.browse_publication') %> + <% end %>

    +
    + +
    + <% + field = Solrizer.solr_name("human_readable_type", :facetable) + item = 'Dataset' + path = main_app.search_catalog_path(search_state.add_facet_params_and_redirect(field, item)) + data = '' + %> +

    <%= link_to path do %> + <%= image_tag 'final-icons-03-100.png', class: "homepage-icon" %> + <% end %>

    +

    <%= link_to path, + class: 'btn btn-primary', + data: data do %> + <%= t('hyrax.browse_dataset') %> + <% end %>

    +
    + +
    + <% + field = Solrizer.solr_name("human_readable_type", :facetable) + item = 'Collection' + path = main_app.search_catalog_path(search_state.add_facet_params_and_redirect(field, item)) + data = '' + %> +

    <%= link_to path do %> + <%= image_tag 'final-icons-05-100.png', class: "homepage-icon" %> + <% end %>

    +

    <%= link_to path, + class: 'btn btn-primary', + data: data do %> + <%= t('hyrax.browse_collection') %> + <% end %>

    +
    +
    diff --git a/hyrax/app/views/hyrax/homepage/_home_share.html.erb b/hyrax/app/views/hyrax/homepage/_home_share.html.erb new file mode 100644 index 00000000..90bd562a --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_home_share.html.erb @@ -0,0 +1,33 @@ +<% if @presenter.display_share_button? %> + <% if signed_in? %> + <% if @presenter.create_many_work_types? %> + <% + link = '#' + data = { behavior: 'select-work', target: '#worktypes-to-create', 'create-type' => 'single' } + %> + <% else # simple link to the first work type %> + <% + link = new_polymorphic_path([main_app, @presenter.first_work_type]) + data = '' + %> + <% end %> + <% else %> + <% + link = hyrax.my_works_path + data = '' + %> + <% end %> +
    +
    +
    <%= link_to link, data: data do %> + <%= image_tag 'final-icons-02-100.png', class: "homepage-icon" %> + <% end %>
    +

    <%= link_to link, + class: 'btn btn-primary', + data: data do %> + <%= t('hyrax.share_button') %> + <% end %>

    +
    <%= link_to t(:'hyrax.pages.tabs.terms_page'), hyrax.terms_path %>
    +
    +
    +<% end %> diff --git a/hyrax/app/views/hyrax/homepage/_recent_document.html.erb b/hyrax/app/views/hyrax/homepage/_recent_document.html.erb new file mode 100644 index 00000000..ac73acc1 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_recent_document.html.erb @@ -0,0 +1,24 @@ +
    + <%= t('hyrax.homepage.recently_uploaded.document.title_label') %> +
    + <%= link_to [main_app, recent_document] do %> + <%= render_thumbnail_tag(recent_document, {width: 90}, {suppress_link: true}) %> + <% end %> +
    +

    + <%= link_to [main_app, recent_document] do %> + <%= truncate(recent_document.to_s, length: 75, separator: ' ') %> + <% end %> +

    +

    + <%= t('hyrax.homepage.recently_uploaded.document.depositor_label') %>: <%= link_to_profile recent_document.depositor(t('hyrax.homepage.recently_uploaded.document.depositor_missing')) %> +

    + +
    diff --git a/hyrax/app/views/hyrax/homepage/_recently_uploaded.html.erb b/hyrax/app/views/hyrax/homepage/_recently_uploaded.html.erb new file mode 100644 index 00000000..568bb059 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/_recently_uploaded.html.erb @@ -0,0 +1,20 @@ +
    +
    +
    +

    <%= t('hyrax.homepage.recently_uploaded.title') %>

    +
    +
    + <% if @recent_documents.blank? %> +
    +
    +

    <%= t('.no_public') %>

    +
    +
    + <% else %> +
    + + <%= render partial: "recent_document", collection: @recent_documents[0,3] %> + +
    + <% end %> +
    diff --git a/hyrax/app/views/hyrax/homepage/index.html.erb b/hyrax/app/views/hyrax/homepage/index.html.erb new file mode 100644 index 00000000..31315210 --- /dev/null +++ b/hyrax/app/views/hyrax/homepage/index.html.erb @@ -0,0 +1,20 @@ +<% provide :page_title, application_name %> + +
    + <%= render 'home_share' %> + <%= render 'home_browse' %> +
    + +
    + <%= render 'featured_works' %> +
    + +
    + <%= render 'recently_uploaded' %> +
    + +
    + <%= render 'featured_researcher' %> +
    + +<%= render '/shared/select_work_type_modal', create_work_presenter: @presenter.create_work_presenter if @presenter.draw_select_work_modal? %> diff --git a/hyrax/app/views/hyrax/images/_attribute_rows.html.erb b/hyrax/app/views/hyrax/images/_attribute_rows.html.erb new file mode 100644 index 00000000..e84e2e30 --- /dev/null +++ b/hyrax/app/views/hyrax/images/_attribute_rows.html.erb @@ -0,0 +1,57 @@ +<%= presenter.attribute_to_html(:date_modified, label: t('hyrax.base.show.last_modified'), html_dl: true) %> + +<% if can? :read_alternative_title, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:alternative_title, label: t('ngdr.fields.alternative_title'), html_dl: true) %> +<% end %> + +<% if can? :read_subject, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %> +<% end %> + +<% if can? :read_publisher, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:publisher, render_as: :faceted, html_dl: true) %> +<% end %> + +<% if can? :read_language, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:language, render_as: :faceted, html_dl: true) %> +<% end %> + +<% if can? :read_keyword, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %> +<% end %> + +<%= presenter.attribute_to_html(:date_created, render_as: :linked, search_field: 'date_created_tesim', html_dl: true) %> + +<% if can? :read_resource_type, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:resource_type, render_as: :faceted, html_dl: true) %> +<% end %> + +<% if can? :read_rights, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:rights_statement, render_as: :rights_statement, html_dl: true) %> +<% end %> + +<% if can? :read_date, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_date, render_as: :nested_date, label: t('ngdr.fields.complex_date'), html_dl: true) %> +<% end %> + +<% if can? :read_identifier, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_identifier, render_as: :nested_identifier, label: t('ngdr.fields.complex_identifier'), html_dl: true) %> +<% end %> + +<% if can? :read_creator, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_person, render_as: :nested_person, label: t('ngdr.fields.complex_person'), html_dl: true) %> +<% end %> + +<% if can? :read_rights, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_rights, render_as: :nested_rights, label: t('ngdr.fields.complex_rights'), html_dl: true) %> +<% end %> + +<% if can? :read_version, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_version, render_as: :nested_version, label: t('ngdr.fields.complex_version'), html_dl: true) %> +<% end %> + +<%= presenter.attribute_to_html(:status, render_as: :faceted, label: "Status", html_dl: true) %> +<%= presenter.attribute_to_html(:instrument, render_as: :faceted, html_dl: true) %> +<%= presenter.attribute_to_html(:specimen_set, render_as: :faceted, label: t('ngdr.fields.specimen_set'), html_dl: true) %> +<%= presenter.attribute_to_html(:complex_relation, render_as: :nested_relation, label: t('ngdr.fields.complex_relation'), html_dl: true) %> +<%= presenter.attribute_to_html(:custom_property, render_as: :nested_custom_property, label: t('ngdr.fields.custom_property'), html_dl: true) %> diff --git a/hyrax/app/views/hyrax/images/_image.html.erb b/hyrax/app/views/hyrax/images/_image.html.erb new file mode 100644 index 00000000..37b9700c --- /dev/null +++ b/hyrax/app/views/hyrax/images/_image.html.erb @@ -0,0 +1,2 @@ +<%# This is a search result view %> +<%= render 'catalog/document', document: image, document_counter: image_counter %> diff --git a/hyrax/app/views/hyrax/publications/_attribute_rows.html.erb b/hyrax/app/views/hyrax/publications/_attribute_rows.html.erb new file mode 100644 index 00000000..607d3768 --- /dev/null +++ b/hyrax/app/views/hyrax/publications/_attribute_rows.html.erb @@ -0,0 +1,76 @@ +<%= presenter.attribute_to_html(:date_modified, label: t('hyrax.base.show.last_modified'), html_dl: true) %> + +<% if can? :read_alternative_title, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:alternative_title, label: t('ngdr.fields.alternative_title'), html_dl: true) %> +<% end %> + +<% if can? :read_subject, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %> +<% end %> + +<% if can? :read_publisher, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:publisher, render_as: :faceted, html_dl: true) %> +<% end %> + +<% if can? :read_language, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:language, render_as: :faceted, html_dl: true) %> +<% end %> + +<% if can? :read_keyword, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %> +<% end %> + +<%= presenter.attribute_to_html(:date_created, render_as: :linked, search_field: 'date_created_tesim', html_dl: true) %> + +<% if can? :read_resource_type, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:resource_type, render_as: :faceted, html_dl: true) %> +<% end %> + +<% if can? :read_rights, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:rights_statement, render_as: :rights_statement, html_dl: true) %> +<% end %> + +<% if can? :read_date, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_date, render_as: :nested_date, label: t('ngdr.fields.complex_date'), html_dl: true) %> +<% end %> + +<% if can? :read_identifier, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_identifier, render_as: :nested_identifier, label: t('ngdr.fields.complex_identifier'), html_dl: true) %> +<% end %> + +<% if can? :read_creator, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_person, render_as: :nested_person, label: t('ngdr.fields.complex_person'), html_dl: true) %> +<% end %> + +<% if can? :read_rights, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_rights, render_as: :nested_rights, label: t('ngdr.fields.complex_rights'), html_dl: true) %> +<% end %> + +<% if can? :read_version, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_version, render_as: :nested_version, label: t('ngdr.fields.complex_version'), html_dl: true) %> +<% end %> + +<% if can? :read_event, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:complex_event, render_as: :nested_event, label: "Event", html_dl: true) %> +<% end %> + +<% if can? :read_issue, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:issue, label: "Issue", html_dl: true) %> +<% end %> + +<% if can? :read_location, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:place, render_as: :faceted, label: "Location", html_dl: true) %> +<% end %> + +<% if can? :read_table_of_contents, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:table_of_contents, label: "Table of contents", html_dl: true) %> +<% end %> + +<% if can? :read_number_of_pages, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:total_number_of_pages, label: "Number of pages", html_dl: true) %> +<% end %> + +<% if can? :read_source, presenter.model_name.name.constantize %> + <%= presenter.attribute_to_html(:source, label: "Source", html_dl: true) %> + <%= presenter.attribute_to_html(:complex_source, render_as: :nested_source, label: t('ngdr.fields.complex_source'), html_dl: true) %> +<% end %> diff --git a/hyrax/app/views/hyrax/publications/_publication.html.erb b/hyrax/app/views/hyrax/publications/_publication.html.erb new file mode 100644 index 00000000..2552f373 --- /dev/null +++ b/hyrax/app/views/hyrax/publications/_publication.html.erb @@ -0,0 +1,2 @@ +<%# This is a search result view %> +<%= render 'catalog/document', document: publication, document_counter: publication_counter %> diff --git a/hyrax/app/views/hyrax/users/_vitals.html.erb b/hyrax/app/views/hyrax/users/_vitals.html.erb new file mode 100644 index 00000000..843b42f6 --- /dev/null +++ b/hyrax/app/views/hyrax/users/_vitals.html.erb @@ -0,0 +1,21 @@ +<%# Override Hyrax - fix bug with number of works search %> +
    + <%= t("hyrax.dashboard.stats.joined_on") %> <%= user.created_at.to_date.strftime("%b %d, %Y") %> +
    + +
    + <%= number_of_collections(user) %> + + <%= link_to t("hyrax.dashboard.stats.works"), main_app.search_catalog_path(f: {generic_type_sim: ['Collection'], depositor_ssim: [user.to_s]}) %> +
    + +
    + <%= number_of_works(user) %> + + <%= link_to t("hyrax.dashboard.stats.works"), main_app.search_catalog_path(f: {generic_type_sim: ['Work'], depositor_ssim: [user.to_s]}) %> + +
      +
    • <%= user.total_file_views %> <%= t("hyrax.dashboard.stats.file_views").pluralize(user.total_file_views) %>
    • +
    • <%= user.total_file_downloads %> <%= t("hyrax.dashboard.stats.file_downloads").pluralize(user.total_file_downloads) %>
    • +
    +
    diff --git a/hyrax/app/views/layouts/application.html.erb b/hyrax/app/views/layouts/application.html.erb index 2a57ce9d..5f0678f4 100644 --- a/hyrax/app/views/layouts/application.html.erb +++ b/hyrax/app/views/layouts/application.html.erb @@ -1,7 +1,7 @@ - Hyrax + <%= application_name %> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> diff --git a/hyrax/app/views/layouts/homepage.html.erb b/hyrax/app/views/layouts/homepage.html.erb new file mode 100644 index 00000000..7bac0119 --- /dev/null +++ b/hyrax/app/views/layouts/homepage.html.erb @@ -0,0 +1,8 @@ +<% content_for(:navbar) do %> +<% end %> + +<% content_for(:precontainer_content) do %> + <%= render 'hyrax/homepage/announcement' if controller_name == 'homepage' %> +<% end %> + +<%= render template: 'layouts/hyrax' %> diff --git a/hyrax/app/views/layouts/hyrax/1_column.html.erb b/hyrax/app/views/layouts/hyrax/1_column.html.erb new file mode 100644 index 00000000..dd16c5fa --- /dev/null +++ b/hyrax/app/views/layouts/hyrax/1_column.html.erb @@ -0,0 +1,5 @@ +<% content_for(:navbar) do %> + <%#= render '/controls' %> +<% end %> + +<%= render template: 'layouts/hyrax' %> diff --git a/hyrax/app/views/records/edit_fields/_characterization_methods.html.erb b/hyrax/app/views/records/edit_fields/_characterization_methods.html.erb new file mode 100644 index 00000000..25cc2b2b --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_characterization_methods.html.erb @@ -0,0 +1,6 @@ +<% service = CharacterizationMethodService.new %> +<%= f.input :characterization_methods, as: :multi_value_select, + collection: service.select_active_options, + include_blank: true, + item_helper: service.method(:include_current_value), + input_html: { class: 'form-control' } %> diff --git a/hyrax/app/views/records/edit_fields/_complex_date.html.erb b/hyrax/app/views/records/edit_fields/_complex_date.html.erb new file mode 100644 index 00000000..0f975b91 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_date.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_date, + as: :nested_date, + input_html: { + class: '', + data: {name: :complex_date} + }, + required: f.object.required?(:complex_date) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_event.html.erb b/hyrax/app/views/records/edit_fields/_complex_event.html.erb new file mode 100644 index 00000000..1ad3f6e3 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_event.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_event, + as: :nested_event, + input_html: { + class: '', + data: {name: :complex_event} + }, + required: f.object.required?(:complex_event) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_identifier.html.erb b/hyrax/app/views/records/edit_fields/_complex_identifier.html.erb new file mode 100644 index 00000000..68057d36 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_identifier.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_identifier, + as: :nested_identifier, + input_html: { + class: '', + data: {name: :complex_identifier} + }, + required: f.object.required?(:complex_identifier) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_instrument.html.erb b/hyrax/app/views/records/edit_fields/_complex_instrument.html.erb new file mode 100644 index 00000000..4fe1d233 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_instrument.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_instrument, + as: :nested_instrument, + input_html: { + class: '', + data: {name: :complex_instrument} + }, + required: f.object.required?(:complex_instrument) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_organization.html.erb b/hyrax/app/views/records/edit_fields/_complex_organization.html.erb new file mode 100644 index 00000000..57eccac6 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_organization.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_organization, + as: :nested_organization, + input_html: { + class: '', + data: {name: :complex_organization} + }, + required: f.object.required?(:complex_organization) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_person.html.erb b/hyrax/app/views/records/edit_fields/_complex_person.html.erb new file mode 100644 index 00000000..b0b60efa --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_person.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_person, + as: :nested_person, + input_html: { + class: '', + data: {name: :complex_person} + }, + required: f.object.required?(:complex_person) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_relation.html.erb b/hyrax/app/views/records/edit_fields/_complex_relation.html.erb new file mode 100644 index 00000000..743c223a --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_relation.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_relation, + as: :nested_relation, + input_html: { + class: '', + data: {name: :complex_relation} + }, + required: f.object.required?(:complex_relation) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_rights.html.erb b/hyrax/app/views/records/edit_fields/_complex_rights.html.erb new file mode 100644 index 00000000..b9aa7925 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_rights.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_rights, + as: :nested_rights, + input_html: { + class: '', + data: {name: :complex_rights} + }, + required: f.object.required?(:complex_rights) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_source.html.erb b/hyrax/app/views/records/edit_fields/_complex_source.html.erb new file mode 100644 index 00000000..462a8eed --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_source.html.erb @@ -0,0 +1,10 @@ +
    + <%= f.input :complex_source, + as: :nested_source, + input_html: { + class: '', + data: {name: :complex_source} + }, + required: f.object.required?(:complex_source) + %> +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_specimen_type.html.erb b/hyrax/app/views/records/edit_fields/_complex_specimen_type.html.erb new file mode 100644 index 00000000..8e044f59 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_specimen_type.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_specimen_type, + as: :nested_specimen_type, + input_html: { + class: '', + data: {name: :complex_specimen_type} + }, + required: f.object.required?(:complex_specimen_type) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_complex_version.html.erb b/hyrax/app/views/records/edit_fields/_complex_version.html.erb new file mode 100644 index 00000000..fb282928 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_version.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :complex_version, + as: :nested_version, + input_html: { + class: '', + data: {name: :complex_version} + }, + required: f.object.required?(:complex_version) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_computational_methods.html.erb b/hyrax/app/views/records/edit_fields/_computational_methods.html.erb new file mode 100644 index 00000000..c7ee5cea --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_computational_methods.html.erb @@ -0,0 +1,6 @@ +<% service = ComputationalMethodService.new %> +<%= f.input :computational_methods, as: :multi_value_select, + collection: service.select_active_options, + include_blank: true, + item_helper: service.method(:include_current_value), + input_html: { class: 'form-control' } %> diff --git a/hyrax/app/views/records/edit_fields/_custom_property.html.erb b/hyrax/app/views/records/edit_fields/_custom_property.html.erb new file mode 100644 index 00000000..149e35bd --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_custom_property.html.erb @@ -0,0 +1,14 @@ +
    + <%= f.input :custom_property, + as: :nested_custom_property, + input_html: { + class: '', + data: {name: :custom_property} + }, + required: f.object.required?(:custom_property) + %> + +
    diff --git a/hyrax/app/views/records/edit_fields/_data_origin.html.erb b/hyrax/app/views/records/edit_fields/_data_origin.html.erb new file mode 100644 index 00000000..4c67395d --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_data_origin.html.erb @@ -0,0 +1,6 @@ +<% service = DataOriginService.new %> +<%= f.input :data_origin, as: :multi_value_select, + collection: service.select_active_options, + include_blank: true, + item_helper: service.method(:include_current_value), + input_html: { class: 'form-control' } %> diff --git a/hyrax/app/views/records/edit_fields/_properties_addressed.html.erb b/hyrax/app/views/records/edit_fields/_properties_addressed.html.erb new file mode 100644 index 00000000..6a7c990d --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_properties_addressed.html.erb @@ -0,0 +1,8 @@ +<% service = PropertiesAddressedService.new %> +<%= f.input :properties_addressed, as: :multi_value_select, + collection: service.select_active_options, + include_blank: true, + item_helper: service.method(:include_current_value), + input_html: { class: 'form-control' } %> + + diff --git a/hyrax/app/views/records/edit_fields/_supervisor_approval.html.erb b/hyrax/app/views/records/edit_fields/_supervisor_approval.html.erb new file mode 100644 index 00000000..19187c23 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_supervisor_approval.html.erb @@ -0,0 +1,8 @@ +<%= f.input :supervisor_approval, + required: f.object.required?(key), + as: :multi_value, + hint: raw("Fill in the name of your supervisor and the date of approval. If you have already got approval on the NIMS Research Presentation Management System (発表許可申請システム), please also fill in the application number (申請番号). + The content (Dataset or Publication) submitted here will be published to the public with yours and your supervisor's consent. See the User's Manual for details. +
    +e.g. Butsuzai, Taro 2019-09-30 2019A00xxxA"), + input_html: {class: 'form-control'} %> diff --git a/hyrax/app/views/records/edit_fields/_synthesis_and_processing.html.erb b/hyrax/app/views/records/edit_fields/_synthesis_and_processing.html.erb new file mode 100644 index 00000000..2963503f --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_synthesis_and_processing.html.erb @@ -0,0 +1,6 @@ +<% service = SynthesisAndProcessingService.new %> +<%= f.input :synthesis_and_processing, as: :multi_value_select, + collection: service.select_active_options, + include_blank: true, + item_helper: service.method(:include_current_value), + input_html: { class: 'form-control' } %> diff --git a/hyrax/app/views/shared/_citations.html.erb b/hyrax/app/views/shared/_citations.html.erb new file mode 100644 index 00000000..4fa1a342 --- /dev/null +++ b/hyrax/app/views/shared/_citations.html.erb @@ -0,0 +1,36 @@ +<% content_for(:twitter_meta) do %> + + + + + + + <% if can? :read_abstract, @presenter.model_name.name.constantize %> + + <% else %> + + <% end %> + + + + + + +<% end %> + +<% content_for(:gscholar_meta) do %> + + <% @presenter.creator.each do |creator| %> + + <% end %> + + + + +<% end %> diff --git a/hyrax/app/views/shared/_footer.html.erb b/hyrax/app/views/shared/_footer.html.erb new file mode 100644 index 00000000..76adc07f --- /dev/null +++ b/hyrax/app/views/shared/_footer.html.erb @@ -0,0 +1,10 @@ +
    +
    +
    +

    <%= t('hyrax.footer.address_html') %>

    +
    +
    +

    <%= t('hyrax.footer.copyright_html') %>

    +
    +
    +
    diff --git a/hyrax/config/analytics.yml b/hyrax/config/analytics.yml index 9abe577c..140b2230 100644 --- a/hyrax/config/analytics.yml +++ b/hyrax/config/analytics.yml @@ -1,9 +1,9 @@ # # To integrate your app with Google Analytics, uncomment the lines below and add your API key information. # -# analytics: -# app_name: GOOGLE_OAUTH_APP_NAME -# app_version: GOOGLE_OAUTH_APP_VERSION -# privkey_path: GOOGLE_OAUTH_PRIVATE_KEY_PATH -# privkey_secret: GOOGLE_OAUTH_PRIVATE_KEY_SECRET -# client_email: GOOGLE_OAUTH_CLIENT_EMAIL +analytics: + app_name: <%= ENV['GA_APP_NAME'] %> + app_version: <%= ENV['GA_APP_VERSION'] %> + privkey_path: <%= ENV['GA_PRIVATE_KEY_PATH'] %> + privkey_secret: <%= ENV['GA_PRIVATE_KEY_SECRET'] %> + client_email: <%= ENV['GA_CLIENT_EMAIL'] %> diff --git a/hyrax/config/application.rb b/hyrax/config/application.rb index ee77b0be..82b8d38e 100644 --- a/hyrax/config/application.rb +++ b/hyrax/config/application.rb @@ -8,9 +8,20 @@ module Hyrax class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + # config.load_defaults 5.1 + # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. + config.active_job.queue_adapter = :sidekiq + + # The locale is set by a query parameter, so if it's not found render 404 + config.action_dispatch.rescue_responses.merge!( + 'I18n::InvalidLocale' => :not_found + ) + + config.action_dispatch.default_headers['Referrer-Policy'] = 'strict-origin-when-cross-origin' end end diff --git a/hyrax/config/authorities.yml b/hyrax/config/authorities.yml new file mode 100644 index 00000000..dd249aec --- /dev/null +++ b/hyrax/config/authorities.yml @@ -0,0 +1 @@ +:local_path: "config/authorities" \ No newline at end of file diff --git a/hyrax/config/authorities/.keep b/hyrax/config/authorities/.keep new file mode 100644 index 00000000..e69de29b diff --git a/hyrax/config/authorities/analysis_fields.yml b/hyrax/config/authorities/analysis_fields.yml new file mode 100644 index 00000000..2ed91801 --- /dev/null +++ b/hyrax/config/authorities/analysis_fields.yml @@ -0,0 +1,49 @@ +terms: +- id: bio property + term: bio property/バイオ特性 + active: true +- id: chemical state + term: chemical state/化学状態 + active: true +- id: crystallograpgy + term: crystallograpgy/結晶学 + active: true +- id: distribution + term: distribution/分布 + active: true +- id: electronic property + term: electronic property/電子的性質 + active: true +- id: environmental analysis + term: environmental analysis/環境分析 + active: true +- id: failuar analysis + term: failuar analysis/故障解析 + active: true +- id: impurity analysis + term: impurity analysis/不純物分析 + active: true +- id: magnetic property + term: magnetic property/磁気特性 + active: true +- id: morphology + term: morphology/形態学 + active: true +- id: optical property + term: optical property/光学特性 + active: true +- id: other (free description) + term: other (free description)/その他(自由記述) + active: true +- id: physical property + term: physical property/物理的特性 + active: true +- id: qualitative analysis + term: qualitative analysis/定性分析 + active: true +- id: quantitative analysis + term: quantitative analysis/定量分析 + active: true +- id: theoretical simulation + term: theoretical simulation/理論的シミュレーション + active: true diff --git a/hyrax/config/authorities/characterization_methods.yml b/hyrax/config/authorities/characterization_methods.yml new file mode 100644 index 00000000..7e2d4e33 --- /dev/null +++ b/hyrax/config/authorities/characterization_methods.yml @@ -0,0 +1,288 @@ +terms: +- id: charge distribution + term: charge distribution/荷電分布 + active: true +- id: charge distribution -- pulsed electroacoustic method + term: charge distribution/荷電分布 -- pulsed electroacoustic method/パルス電気音響法 + active: true +- id: chromatography + term: chromatography/クロマトグラフィー + active: true +- id: chromatography -- critical and supercritical chromatography + term: chromatography/クロマトグラフィー -- critical and supercritical chromatography/クリティカルと超臨界クロマトグラフィー + active: true +- id: chromatography -- gas-phase chromatography + term: chromatography/クロマトグラフィー -- gas-phase chromatography/気相クロマトグラフィー + active: true +- id: chromatography -- ion chromatography + term: chromatography/クロマトグラフィー -- ion chromatography/イオンクロマトグラフィー + active: true +- id: chromatography -- liquid-phase chromatography + term: chromatography/クロマトグラフィー -- liquid-phase chromatography/液相クロマトグラフィー + active: true +- id: dilatometry + term: dilatometry/膨張計 + active: true +- id: electrochemical + term: electrochemical/電気化学 + active: true +- id: electrochemical -- amperometry + term: electrochemical/電気化学 -- amperometry/アンペロメトリー + active: true +- id: electrochemical -- potentiometry + term: electrochemical/電気化学 -- potentiometry/電位差測定法 + active: true +- id: electrochemical -- voltammetry + term: electrochemical/電気化学 -- voltammetry/ボルタンメトリー + active: true +- id: mechanical + term: mechanical/機械特性 + active: true +- id: mechanical -- compression tests + term: mechanical/機械特性 -- compression tests/圧縮試験 + active: true +- id: mechanical -- creep tests + term: mechanical/機械特性 -- creep tests/クリープテスト + active: true +- id: mechanical -- dynamic mechanical analysis + term: mechanical/機械特性 -- dynamic mechanical analysis/動的機械的分析 + active: true +- id: mechanical -- hardness + term: mechanical/機械特性 -- hardness/硬度 + active: true +- id: mechanical -- nanoindentation + term: mechanical/機械特性 -- nanoindentation/ナノインデンテーション + active: true +- id: mechanical -- shear or torsion tests + term: mechanical/機械特性 -- shear or torsion tests/せん断試験またはねじり試験 + active: true +- id: mechanical -- tension tests + term: mechanical/機械特性 -- tension tests/張力試験 + active: true +- id: mechanical -- wear tests + term: mechanical/機械特性 -- wear tests/摩耗試験 + active: true +- id: microscopy + term: microscopy/顕微鏡法 + active: true +- id: microscopy -- analytical electron microscopy + term: microscopy/顕微鏡法 -- analytical electron microscopy/分析電子顕微鏡法 + active: true +- id: microscopy -- atomic force microscopy + term: microscopy/顕微鏡法 -- atomic force microscopy/原子間力顕微鏡 + active: true +- id: microscopy -- confocal microscopy + term: microscopy/顕微鏡法 -- confocal microscopy/共焦点顕微鏡法 + active: true +- id: microscopy -- electron probe microanalysis + term: microscopy/顕微鏡法 -- electron probe microanalysis/電子プローブ微量分析 + active: true +- id: microscopy -- environmental scanning electron + term: microscopy/顕微鏡法 -- environmental scanning electron/環境走査型電子顕微鏡 + active: true +- id: microscopy -- field emission electron probe + term: |- + microscopy/顕微鏡法 -- microscopy + field emission electron probe/電界放出電子プローブ + active: true +- id: microscopy -- optical microscopy + term: microscopy/顕微鏡法 -- optical microscopy/光学顕微鏡法 + active: true +- id: microscopy -- photoluminescence microscopy + term: microscopy/顕微鏡法 -- photoluminescence microscopy/フォトルミネセンス顕微鏡 + active: true +- id: microscopy -- scanning Auger electron microscopy + term: microscopy/顕微鏡法 -- scanning Auger electron microscopy/走査型オージェ電子顕微鏡法 + active: true +- id: microscopy -- scanning Kelvin probe + term: microscopy/顕微鏡法 -- scanning Kelvin probe/スキャニングケルビンプローブ + active: true +- id: microscopy -- scanning electron microscopy + term: microscopy/顕微鏡法 -- scanning electron microscopy/電子顕微鏡 + active: true +- id: microscopy -- scanning probe microscopy + term: microscopy/顕微鏡法 -- scanning probe microscopy/走査型プローブ顕微鏡法 + active: true +- id: microscopy -- scanning transmission electron microscopy + term: microscopy/顕微鏡法 -- scanning transmission electron microscopy/走査透過電子顕微鏡法 + active: true +- id: microscopy -- scanning tunneling microscopy + term: microscopy/顕微鏡法 -- scanning tunneling microscopy/走査トンネル顕微鏡 + active: true +- id: microscopy -- transmission electron microscopy + term: microscopy/顕微鏡法 -- transmission electron microscopy/透過電子顕微鏡法 + active: true +- id: microscopy -- x-ray optical interferometry + term: microscopy/顕微鏡法 -- x-ray optical interferometry/X線光学干渉法 + active: true +- id: optical + term: optical/光学測定 + active: true +- id: optical -- differential refractive index + term: optical/光学測定 -- differential refractive index/示差屈折率 + active: true +- id: optical -- dynamic light scattering + term: optical/光学測定 -- dynamic light scattering/動的光散乱 + active: true +- id: optical -- ellipsometry + term: optical/光学測定 -- ellipsometry/エリプソメトリー + active: true +- id: optical -- fractography + term: optical/光学測定 -- fractography/フラクトグラフィ + active: true +- id: optical -- light scattering + term: optical/光学測定 -- light scattering/光散乱 + active: true +- id: optical -- quasi-elastic light scattering + term: optical/光学測定 -- quasi-elastic light scattering/準弾性光散乱 + active: true +- id: osmometry + term: osmometry/浸透圧法(osmometry) + active: true +- id: osmometry -- freezing point depression osmometry + term: osmometry/浸透圧法(osmometry) -- freezing point depression osmometry/凝固点降下 + active: true +- id: osmometry -- membrane osmometry + term: osmometry/浸透圧法(osmometry) -- membrane osmometry/膜浸透圧測定 + active: true +- id: osmometry -- vapor pressure depression osmometry + term: osmometry/浸透圧法(osmometry) -- vapor pressure depression osmometry/蒸気圧低下浸透圧法 + active: true +- id: profilometry + term: profilometry/プロフィロメトリー + active: true +- id: scattering and diffraction + term: scattering and diffraction/散乱_回折 + active: true +- id: scattering and diffraction -- XRD grazing incidence + term: scattering and diffraction/散乱_回折 -- XRD grazing incidence/XRD低角入射 + active: true +- id: scattering and diffraction -- electron backscatter diffraction + term: scattering and diffraction/散乱_回折 -- electron backscatter diffraction/電子バックスキャッタ回折 + active: true +- id: scattering and diffraction -- neutron (elastic) + term: scattering and diffraction/散乱_回折 -- neutron (elastic)/中性子(弾性) + active: true +- id: scattering and diffraction -- neutron (inelastic) + term: scattering and diffraction/散乱_回折 -- neutron (inelastic)/中性子(非弾性) + active: true +- id: scattering and diffraction -- small angle x-ray scattering + term: scattering and diffraction/散乱_回折 -- small angle x-ray scattering/小角X線散乱_極小角X線散乱 + active: true +- id: scattering and diffraction -- small-angle neutron scattering + term: scattering and diffraction/散乱_回折 -- small-angle neutron scattering/小角中性子 + active: true +- id: scattering and diffraction -- synchrotron + term: scattering and diffraction/散乱_回折 -- synchrotron/シンクロトロン利用 + active: true +- id: scattering and diffraction -- x-ray diffraction + term: scattering and diffraction/散乱_回折 -- x-ray diffraction/X線回折 + active: true +- id: scattering and diffraction -- x-ray reflectivity + term: scattering and diffraction/散乱_回折 -- x-ray reflectivity/X線反射率 + active: true +- id: scattering and diffraction -- x-ray topography + term: scattering and diffraction/散乱_回折 -- x-ray topography/X線トポグラフィ + active: true +- id: spectrometry + term: spectrometry/分光分析法 + active: true +- id: spectrometry -- IR_FTIR spectrometry + term: spectrometry/分光分析法 -- IR_FTIR spectrometry/IR _ FTIR分光測定 + active: true +- id: spectrometry -- alpha spectrometry + term: spectrometry/分光分析法 -- alpha spectrometry/アルファ分光法 + active: true +- id: spectrometry -- energy dispersive x-ray spectometry + term: spectrometry/分光分析法 -- energy dispersive x-ray spectometry/エネルギー分散型X線分光法 + active: true +- id: spectrometry -- gamma spectrometry + term: spectrometry/分光分析法 -- gamma spectrometry/ガンマ線分光法 + active: true +- id: spectrometry -- ion mobility spectrometry + term: spectrometry/分光分析法 -- ion mobility spectrometry/イオン移動度分光法 + active: true +- id: spectrometry -- mass spectrometry + term: spectrometry/分光分析法 -- mass spectrometry/質量分析 + active: true +- id: spectrometry -- secondary ion mass spectrometry + term: spectrometry/分光分析法 -- secondary ion mass spectrometry/二次イオン質量分析法 + active: true +- id: spectrometry -- x-ray flourescence spectrometry + term: spectrometry/分光分析法 -- x-ray flourescence spectrometry/X線蛍光分光分析 + active: true +- id: spectroscopy + term: spectroscopy/分光法 + active: true +- id: spectroscopy -- EXAFS + term: spectroscopy/分光法 -- EXAFS/EXAFS + active: true +- id: spectroscopy -- Fourier-transform infrared spectroscopy + term: spectroscopy/分光法 -- Fourier-transform infrared spectroscopy/フーリエ変換赤外分光法 + active: true +- id: spectroscopy -- NEXAFS + term: spectroscopy/分光法 -- NEXAFS/NEXAFS + active: true +- id: spectroscopy -- NMR + term: spectroscopy/分光法 -- NMR/NMR + active: true +- id: spectroscopy -- Raman + term: spectroscopy/分光法 -- Raman/ラマン + active: true +- id: spectroscopy -- XPS variable kinetic + term: spectroscopy/分光法 -- XPS variable kinetic/XPS入射光可変 + active: true +- id: spectroscopy -- dielectric and impedance spectroscopy + term: spectroscopy/分光法 -- dielectric and impedance spectroscopy/誘電体_インピーダンス分光法 + active: true +- id: spectroscopy -- dynamic mechanical spectroscopy + term: spectroscopy/分光法 -- dynamic mechanical spectroscopy/動的機械的分析 + active: true +- id: spectroscopy -- electron energy-loss spectroscopy + term: spectroscopy/分光法 -- electron energy-loss spectroscopy/電子エネルギー損失分光法 + active: true +- id: spectroscopy -- x-ray absorption spectroscopy + term: spectroscopy/分光法 -- x-ray absorption spectroscopy/X線吸収分光法 + active: true +- id: spectroscopy -- x-ray emission spectroscopy + term: spectroscopy/分光法 -- x-ray emission spectroscopy/X線発光分光法 + active: true +- id: spectroscopy -- x-ray photoelectron spectroscopy + term: spectroscopy/分光法 -- x-ray photoelectron spectroscopy/X線光電子分光法 + active: true +- id: thermochemical + term: thermochemical/熱化学 + active: true +- id: thermochemical -- calorimetry + term: thermochemical/熱化学 -- calorimetry/熱量測定 + active: true +- id: thermochemical -- differential scanning calorimetry + term: thermochemical/熱化学 -- differential scanning calorimetry/示差走査熱量測定 + active: true +- id: thermochemical -- differential thermal analysis + term: thermochemical/熱化学 -- differential thermal analysis/示差熱分析 + active: true +- id: thermochemical -- microcalorimetry + term: thermochemical/熱化学 -- microcalorimetry/微量熱量測定 + active: true +- id: thermochemical -- thermogravimetry + term: thermochemical/熱化学 -- thermogravimetry/熱重量測定 + active: true +- id: tomography + term: tomography/トモグラフィー + active: true +- id: tomography -- atom probe tomography + term: tomography/トモグラフィー -- atom probe tomography/原子プローブトモグラフィー + active: true +- id: tomography -- x-ray tomography + term: tomography/トモグラフィー -- x-ray tomography/X線断層撮影 + active: true +- id: ultrasonic + term: ultrasonic/超音波 + active: true +- id: viscometry + term: viscometry/粘度測定 + active: true +- id: other + term: other/その他 + active: true diff --git a/hyrax/config/authorities/computational_methods.yml b/hyrax/config/authorities/computational_methods.yml new file mode 100644 index 00000000..7476c82c --- /dev/null +++ b/hyrax/config/authorities/computational_methods.yml @@ -0,0 +1,59 @@ +terms: +- id: CALPHAD + term: CALPHAD/カルパッド + active: true +- id: Monte Carlo methods + term: Monte Carlo methods/モンテカルロ法 + active: true +- id: boundary tracking or level set + term: boundary tracking or level set/境界トラッキングまたはレベルセット + active: true +- id: cellular automata + term: cellular automata/セルオートマトン + active: true +- id: cluster expansion + term: cluster expansion/クラスタ拡張 + active: true +- id: crystal plasticity + term: crystal plasticity/結晶の可塑性 + active: true +- id: density functional theory or electronic structure + term: density functional theory or electronic structure/密度汎関数理論または電子構造 + active: true +- id: dislocation dynamics + term: dislocation dynamics/転位ダイナミクス + active: true +- id: finite element analysis + term: finite element analysis/有限要素解析 + active: true +- id: machine learning + term: machine learning/機械学習 + active: true +- id: molecular dynamics + term: molecular dynamics/分子動力学 + active: true +- id: multiscale simulations + term: multiscale simulations/マルチスケールシミュレーション + active: true +- id: phase-field calculations + term: phase-field calculations/位相場計算 + active: true +- id: reverse Monte Carlo + term: reverse Monte Carlo/リバースモンテカルロ + active: true +- id: scattering theory + term: scattering theory/散乱理論 + active: true +- id: self-consistent field theory + term: self-consistent field theory/自己一貫性場理論 + active: true +- id: simulated experiment + term: simulated experiment/シミュレート実験 + active: true +- id: statistical mechanics + term: statistical mechanics/統計力学 + active: true +- id: other + term: other/その他 + active: true + diff --git a/hyrax/config/authorities/data_origin.yml b/hyrax/config/authorities/data_origin.yml new file mode 100644 index 00000000..0402033c --- /dev/null +++ b/hyrax/config/authorities/data_origin.yml @@ -0,0 +1,16 @@ +terms: +- id: experiments + term: experiments/実験 + active: true +- id: informatics and data science + term: informatics and data science/情報・データ科学 + active: true +- id: other + term: other/その他 + active: true +- id: simulations + term: simulations/シミュレーション + active: true +- id: theory + term: theory/理論 + active: true diff --git a/hyrax/config/authorities/dates.yml b/hyrax/config/authorities/dates.yml new file mode 100644 index 00000000..3388ac90 --- /dev/null +++ b/hyrax/config/authorities/dates.yml @@ -0,0 +1,43 @@ +terms: + - id: http://purl.org/dc/terms/dateAccepted + term: Accepted + active: true + - id: Available + term: Available + active: true + - id: http://bibframe.org/vocab/copyrightDate + term: Copyrighted + active: true + - id: Collected + term: Collected + active: true + - id: http://purl.org/dc/terms/created + term: Created + active: true + - id: Deposited + term: Deposited + active: true + - id: http://purl.org/dc/terms/issued + term: Issued + active: true + - id: Published + term: Published + active: true + - id: http://bibframe.org/vocab/providerDate + term: Submitted + active: true + - id: http://bibframe.org/vocab/changeDate + term: Updated + active: true + - id: http://purl.org/dc/terms/valid + term: Valid + active: true + - id: Processed + term: Processed + active: true + - id: Purchased + term: Purchased + active: true + - id: Registered + term: Registered + active: true diff --git a/hyrax/config/authorities/identifiers.yml b/hyrax/config/authorities/identifiers.yml new file mode 100644 index 00000000..b0c81ae5 --- /dev/null +++ b/hyrax/config/authorities/identifiers.yml @@ -0,0 +1,55 @@ +terms: + - id: identifier local + term: Identifier - Local + active: true + - id: identifier persistent + term: Identifier - Persistent + active: true + - id: DOI + term: DOI + active: true + - id: handle identifier + term: Handle identifier + active: true + - id: edu person principal name + term: eduPersonPrincipalName + active: true + - id: edu person targeted id + term: eduPersonTargetedID + active: true + - id: full image url + term: Full Image URL + active: true + - id: ORCID + term: ORCID + active: true + - id: project id + term: Project ID + active: true + - id: referred identifier local + term: Referred Identifier - Local + active: true + - id: referred identifier persistent + term: Referred Identifier - Persistent + active: true + - id: related identifier local + term: Related Identifier - Local + active: true + - id: related identifier persistent + term: Related Identifier - Persistent + active: true + - id: thumbnail image url + term: Thumbnail Image URL + active: true + - id: web image url + term: Web Image URL + active: true + - id: previous identifier + term: Previous identifier + active: true + - id: CAS + term: CAS + active: true + - id: other + term: Other + active: true diff --git a/hyrax/config/authorities/licenses.yml b/hyrax/config/authorities/licenses.yml index 89dd602a..653aff47 100644 --- a/hyrax/config/authorities/licenses.yml +++ b/hyrax/config/authorities/licenses.yml @@ -1,25 +1,7 @@ terms: - - id: http://creativecommons.org/licenses/by/3.0/us/ - term: Attribution 3.0 United States - active: false - - id: http://creativecommons.org/licenses/by-sa/3.0/us/ - term: Attribution-ShareAlike 3.0 United States - active: false - - id: http://creativecommons.org/licenses/by-nc/3.0/us/ - term: Attribution-NonCommercial 3.0 United States - active: false - - id: http://creativecommons.org/licenses/by-nd/3.0/us/ - term: Attribution-NoDerivs 3.0 United States - active: false - - id: http://creativecommons.org/licenses/by-nc-nd/3.0/us/ - term: Attribution-NonCommercial-NoDerivs 3.0 United States - active: false - - id: http://creativecommons.org/licenses/by-nc-sa/3.0/us/ - term: Attribution-NonCommercial-ShareAlike 3.0 United States - active: false - - id: http://www.europeana.eu/portal/rights/rr-r.html - term: All rights reserved - active: false + - id: http://rightsstatements.org/vocab/InC/1.0/ + term: In Copyright + active: true - id: https://creativecommons.org/licenses/by/4.0/ term: Creative Commons BY Attribution 4.0 International active: true @@ -44,3 +26,12 @@ terms: - id: http://creativecommons.org/publicdomain/mark/1.0/ term: Creative Commons Public Domain Mark 1.0 active: true + - id: http://www.apache.org/licenses/LICENSE-2.0 + term: Apache License 2.0 + active: true + - id: http://www.gnu.org/licenses/gpl.html + term: GNU General Public License + active: true + - id: http://opensource.org/licenses/MIT + term: MIT License + active: true diff --git a/hyrax/config/authorities/material_types.yml b/hyrax/config/authorities/material_types.yml new file mode 100644 index 00000000..e7ba1355 --- /dev/null +++ b/hyrax/config/authorities/material_types.yml @@ -0,0 +1,142 @@ +terms: +- id: biological + term: biological/生物学的物質 + active: true +- id: biomaterials + term: biomaterials/生体材料 + active: true +- id: ceramics + term: ceramics/セラミックス + active: true +- id: ceramics -- carbides + term: ceramics/セラミックス -- carbides/炭化物 + active: true +- id: ceramics -- cements + term: ceramics/セラミックス -- cements/セメント + active: true +- id: ceramics -- nitrides + term: ceramics/セラミックス -- nitrides/窒化物 + active: true +- id: ceramics -- oxides + term: ceramics/セラミックス -- oxides/酸化物 + active: true +- id: ceramics -- perovskites + term: ceramics/セラミックス -- perovskites/ペロブスカイト + active: true +- id: ceramics -- silicates + term: ceramics/セラミックス -- silicates/シリケート + active: true +- id: metals and alloys + term: metals and alloys/金属・合金 + active: true +- id: metals and alloys -- Al-containing + term: metals and alloys/金属・合金 -- Al-containing/Al含有物質 + active: true +- id: metals and alloys -- Cu-containing + term: metals and alloys/金属・合金 -- Cu-containing/Cu含有物質 + active: true +- id: metals and alloys -- Fe-containing + term: metals and alloys/金属・合金 -- Fe-containing/Fe含有物質 + active: true +- id: metals and alloys -- Mg-containing + term: metals and alloys/金属・合金 -- Mg-containing/Mg含有物質 + active: true +- id: metals and alloys -- Ni-containing + term: metals and alloys/金属・合金 -- Ni-containing/Ni含有物質 + active: true +- id: metals and alloys -- Ti-containing + term: metals and alloys/金属・合金 -- Ti-containing/Ti含有物質 + active: true +- id: metals and alloys -- commercially pure metals + term: metals and alloys/金属・合金 -- commercially pure metals/商用純粋金属 + active: true +- id: metals and alloys -- intermetallics + term: metals and alloys/金属・合金 -- intermetallics/金属間化合物 + active: true +- id: metals and alloys -- rare earths + term: metals and alloys/金属・合金 -- rare earths/希土類 + active: true +- id: metals and alloys -- refractories + term: metals and alloys/金属・合金 -- refractories/耐火物 + active: true +- id: metals and alloys -- steels + term: metals and alloys/金属・合金 -- steels/鋼 + active: true +- id: metals and alloys -- superalloys + term: metals and alloys/金属・合金 -- superalloys/超合金 + active: true +- id: metamaterials + term: metamaterials/メタマテリアル + active: true +- id: molecular fluids + term: molecular fluids/分子流体 + active: true +- id: organic compounds + term: organic compounds/有機化合物 + active: true +- id: organic compounds -- amines + term: organic compounds/有機化合物 -- amines/アミン類 + active: true +- id: organic compounds -- carboxylic acids + term: organic compounds/有機化合物 -- carboxylic acids/カルボン酸 + active: true +- id: organic compounds -- nitriles + term: organic compounds/有機化合物 -- nitriles/ニトリル + active: true +- id: organometallics + term: organometallics/有機金属 + active: true +- id: polymers + term: polymers/ポリマー + active: true +- id: polymers -- copolymers + term: polymers/ポリマー -- copolymers/コポリマー + active: true +- id: polymers -- elastomers + term: polymers/ポリマー -- elastomers/エラストマー + active: true +- id: polymers -- homopolymers + term: polymers/ポリマー -- homopolymers/ホモポリマー + active: true +- id: polymers -- liquid crystals + term: polymers/ポリマー -- liquid crystals/液晶 + active: true +- id: polymers -- polymer blends + term: polymers/ポリマー -- polymer blends/ポリマーブレンド + active: true +- id: polymers -- rubbers + term: polymers/ポリマー -- rubbers/ゴム + active: true +- id: polymers -- thermoplastics + term: polymers/ポリマー -- thermoplastics/熱可塑性プラスチック + active: true +- id: polymers -- thermosets + term: polymers/ポリマー -- thermosets/熱硬化性樹脂 + active: true +- id: semiconductors + term: semiconductors/半導体 + active: true +- id: semiconductors -- II-VI + term: semiconductors/半導体 -- II-VI/II-VI + active: true +- id: semiconductors -- III-V + term: semiconductors/半導体 -- III-V/III-V + active: true +- id: semiconductors -- extrinsic + term: semiconductors/半導体 -- extrinsic/外因性(extrinsic) + active: true +- id: semiconductors -- intrinsic + term: semiconductors/半導体 -- intrinsic/固有(intrinsic) + active: true +- id: semiconductors -- n-type + term: semiconductors/半導体 -- n-type/n型 + active: true +- id: semiconductors -- nitrides + term: semiconductors/半導体 -- nitrides/窒化物 + active: true +- id: semiconductors -- p-type + term: semiconductors/半導体 -- p-type/p型 + active: true +- id: semiconductors -- silicon + term: semiconductors/半導体 -- silicon/シリコン + active: true diff --git a/hyrax/config/authorities/measurement_environments.yml b/hyrax/config/authorities/measurement_environments.yml new file mode 100644 index 00000000..806a7631 --- /dev/null +++ b/hyrax/config/authorities/measurement_environments.yml @@ -0,0 +1,25 @@ +terms: +- id: at low temperature + term: at low temperature/低温 + active: true +- id: in air + term: in air/空気中 + active: true +- id: in high pressure + term: in high pressure/高圧下 + active: true +- id: in inactive gas + term: in inactive gas/不活性ガス中 + active: true +- id: in liquid + term: in liquid/液体中 + active: true +- id: in magnetic field + term: in magnetic field/磁場中 + active: true +- id: in vacuum + term: in vacuum/真空中 + active: true +- id: other (free description) + term: other (free description)/その他(自由記述) + active: true diff --git a/hyrax/config/authorities/processing_environments.yml b/hyrax/config/authorities/processing_environments.yml new file mode 100644 index 00000000..806a7631 --- /dev/null +++ b/hyrax/config/authorities/processing_environments.yml @@ -0,0 +1,25 @@ +terms: +- id: at low temperature + term: at low temperature/低温 + active: true +- id: in air + term: in air/空気中 + active: true +- id: in high pressure + term: in high pressure/高圧下 + active: true +- id: in inactive gas + term: in inactive gas/不活性ガス中 + active: true +- id: in liquid + term: in liquid/液体中 + active: true +- id: in magnetic field + term: in magnetic field/磁場中 + active: true +- id: in vacuum + term: in vacuum/真空中 + active: true +- id: other (free description) + term: other (free description)/その他(自由記述) + active: true diff --git a/hyrax/config/authorities/properties_addressed.yml b/hyrax/config/authorities/properties_addressed.yml new file mode 100644 index 00000000..3989a037 --- /dev/null +++ b/hyrax/config/authorities/properties_addressed.yml @@ -0,0 +1,339 @@ +terms: +- id: chemical + term: chemical/化学的 + active: true +- id: chemical -- composition + term: chemical/化学的 -- composition/組成 + active: true +- id: chemical -- impurity concentration + term: chemical/化学的 -- impurity concentration/不純物濃度 + active: true +- id: chemical -- molecular masses and distributions + term: chemical/化学的 -- molecular masses and distributions/分子量_分布 + active: true +- id: colligative + term: colligative/束一性 + active: true +- id: corrosion + term: corrosion/腐食 + active: true +- id: corrosion -- crevice + term: corrosion/腐食 -- crevice/隙間(crevice) + active: true +- id: corrosion -- erosion-corrosion + term: corrosion/腐食 -- erosion-corrosion/侵食腐食 + active: true +- id: corrosion -- galvanic + term: corrosion/腐食 -- galvanic/ガルバニック + active: true +- id: corrosion -- high temperature + term: corrosion/腐食 -- high temperature/高温 + active: true +- id: corrosion -- intergranular + term: corrosion/腐食 -- intergranular/粒子間 + active: true +- id: corrosion -- pitting + term: corrosion/腐食 -- pitting/ピッティング + active: true +- id: corrosion -- selective leaching + term: corrosion/腐食 -- selective leaching/選択的浸出 + active: true +- id: corrosion -- stress corrosion + term: corrosion/腐食 -- stress corrosion/応力腐食 + active: true +- id: corrosion -- uniform + term: corrosion/腐食 -- uniform/均一 + active: true +- id: crystallographic + term: crystallographic/結晶学的 + active: true +- id: crystallographic -- crystalline lattice + term: crystallographic/結晶学的 -- crystalline lattice/結晶格子 + active: true +- id: crystallographic -- orientation maps + term: crystallographic/結晶学的 -- orientation maps/方位マップ + active: true +- id: crystallographic -- space groups + term: crystallographic/結晶学的 -- space groups/空間群 + active: true +- id: crystallographic -- textures + term: crystallographic/結晶学的 -- textures/テクスチャ + active: true +- id: durability + term: durability/耐久性 + active: true +- id: durability -- aging + term: durability/耐久性 -- aging/エージング + active: true +- id: durability -- coefficient of friction + term: durability/耐久性 -- coefficient of friction/摩擦係数 + active: true +- id: durability -- thermal shock resistance + term: durability/耐久性 -- thermal shock resistance/耐熱衝撃性 + active: true +- id: durability -- wear resistance + term: durability/耐久性 -- wear resistance/耐摩耗性 + active: true +- id: electrical + term: electrical/電気特性 + active: true +- id: electrical -- band structure + term: electrical/電気特性 -- band structure/バンド構造 + active: true +- id: electrical -- conductivity + term: electrical/電気特性 -- conductivity/導電性 + active: true +- id: electrical -- dielectric constant and spectra + term: electrical/電気特性 -- dielectric constant and spectra/誘電率_スペクトル + active: true +- id: electrical -- dielectric dispersion + term: electrical/電気特性 -- dielectric dispersion/誘電体分散 + active: true +- id: electrical -- electrostrictive + term: electrical/電気特性 -- electrostrictive/電歪 + active: true +- id: electrical -- piezoelectric + term: electrical/電気特性 -- piezoelectric/圧電 + active: true +- id: electrical -- power conversion efficiency + term: electrical/電気特性 -- power conversion efficiency/電力変換効率 + active: true +- id: electrical -- pyroelectric + term: electrical/電気特性 -- pyroelectric/焦電 + active: true +- id: electrical -- resistivity + term: electrical/電気特性 -- resistivity/抵抗率 + active: true +- id: electrical -- spin polarization + term: electrical/電気特性 -- spin polarization/スピン偏極 + active: true +- id: electrical -- superconductivity + term: electrical/電気特性 -- superconductivity/超伝導 + active: true +- id: electrical -- thermoelectric + term: electrical/電気特性 -- thermoelectric/熱電 + active: true +- id: kinetic + term: kinetic/動的 + active: true +- id: kinetic -- grain growth + term: kinetic/動的 -- grain growth/粒成長 + active: true +- id: kinetic -- phase evolution + term: kinetic/動的 -- phase evolution/位相進化 + active: true +- id: kinetic -- phase transitions and ordering + term: kinetic/動的 -- phase transitions and ordering/相転移_秩序性 + active: true +- id: magnetic + term: magnetic/磁性 + active: true +- id: magnetic -- Curie temperature + term: magnetic/磁性 -- Curie temperature/キュリー温度 + active: true +- id: magnetic -- coercivity + term: magnetic/磁性 -- coercivity/保磁力(coercivity) + active: true +- id: magnetic -- magnetization + term: magnetic/磁性 -- magnetization/磁化 + active: true +- id: magnetic -- permeability + term: magnetic/磁性 -- permeability/透過性 + active: true +- id: magnetic -- saturation magnetization + term: magnetic/磁性 -- saturation magnetization/飽和磁化 + active: true +- id: magnetic -- susceptibility + term: magnetic/磁性 -- susceptibility/感受性(susceptibility) + active: true +- id: mechanical + term: mechanical/機械的性質 + active: true +- id: mechanical -- Poisson's ratio + term: mechanical/機械的性質 -- Poisson's ratio/ポアソン比 + active: true +- id: mechanical -- acoustic emission + term: mechanical/機械的性質 -- acoustic emission/音響放射 + active: true +- id: mechanical -- compression response + term: mechanical/機械的性質 -- compression response/圧縮応答 + active: true +- id: mechanical -- creep + term: mechanical/機械的性質 -- creep/クリープ + active: true +- id: mechanical -- deformation mechanisms + term: mechanical/機械的性質 -- deformation mechanisms/変形メカニズム + active: true +- id: mechanical -- ductility + term: mechanical/機械的性質 -- ductility/延性 + active: true +- id: mechanical -- elasticity + term: mechanical/機械的性質 -- elasticity/弾性 + active: true +- id: mechanical -- fatigue + term: mechanical/機械的性質 -- fatigue/疲労 + active: true +- id: mechanical -- flexural response + term: mechanical/機械的性質 -- flexural response/曲げ応答 + active: true +- id: mechanical -- fracture behavior + term: mechanical/機械的性質 -- fracture behavior/破壊挙動 + active: true +- id: mechanical -- fracture toughness + term: mechanical/機械的性質 -- fracture toughness/破壊靭性 + active: true +- id: mechanical -- hardness + term: mechanical/機械的性質 -- hardness/硬度 + active: true +- id: mechanical -- impact response + term: mechanical/機械的性質 -- impact response/衝撃応答 + active: true +- id: mechanical -- phonon modes + term: mechanical/機械的性質 -- phonon modes/フォノンモード + active: true +- id: mechanical -- plasticity + term: mechanical/機械的性質 -- plasticity/可塑性 + active: true +- id: mechanical -- shear response + term: mechanical/機械的性質 -- shear response/せん断応答 + active: true +- id: mechanical -- strength + term: mechanical/機械的性質 -- strength/力 + active: true +- id: mechanical -- stress-strain behavior + term: mechanical/機械的性質 -- stress-strain behavior/応力 - ひずみ挙動 + active: true +- id: mechanical -- tensile response + term: mechanical/機械的性質 -- tensile response/引張応答 + active: true +- id: mechanical -- tensile strength + term: mechanical/機械的性質 -- tensile strength/抗張力 + active: true +- id: mechanical -- viscoelasticity + term: mechanical/機械的性質 -- viscoelasticity/粘弾性 + active: true +- id: mechanical -- yield strength + term: mechanical/機械的性質 -- yield strength/降伏強度 + active: true +- id: optical + term: optical/光学的性質 + active: true +- id: optical -- index of refraction + term: optical/光学的性質 -- index of refraction/屈折率 + active: true +- id: optical -- luminescence + term: optical/光学的性質 -- luminescence/発光 + active: true +- id: optical -- photoconductivity + term: optical/光学的性質 -- photoconductivity/光伝導性 + active: true +- id: rheological + term: rheological/レオロジー(流動学)的性質 + active: true +- id: rheological -- complex modulus + term: rheological/レオロジー(流動学)的性質 -- complex modulus/複素弾性率 + active: true +- id: rheological -- viscoelasticity + term: rheological/レオロジー(流動学)的性質 -- viscoelasticity/粘弾性 + active: true +- id: rheological -- viscosity + term: rheological/レオロジー(流動学)的性質 -- viscosity/粘度 + active: true +- id: structural + term: structural/構造的性質 + active: true +- id: thermodynamic + term: thermodynamic/熱力学的性質 + active: true +- id: thermodynamic -- calorimetry profile + term: thermodynamic/熱力学的性質 -- calorimetry profile/熱量測定プロファイル + active: true +- id: thermodynamic -- critical temperatures + term: thermodynamic/熱力学的性質 -- critical temperatures/臨界温度 + active: true +- id: thermodynamic -- crystallization temperature + term: thermodynamic/熱力学的性質 -- crystallization temperature/結晶化温度 + active: true +- id: thermodynamic -- density + term: thermodynamic/熱力学的性質 -- density/密度 + active: true +- id: thermodynamic -- glass transition temperature + term: thermodynamic/熱力学的性質 -- glass transition temperature/ガラス転移温度 + active: true +- id: thermodynamic -- grain boundary energies + term: thermodynamic/熱力学的性質 -- grain boundary energies/粒界エネルギー + active: true +- id: thermodynamic -- heat capacity + term: thermodynamic/熱力学的性質 -- heat capacity/熱容量 + active: true +- id: thermodynamic -- heat of fusion + term: thermodynamic/熱力学的性質 -- heat of fusion/融合熱 + active: true +- id: thermodynamic -- heat of solidification + term: thermodynamic/熱力学的性質 -- heat of solidification/凝固熱 + active: true +- id: thermodynamic -- interfacial energies + term: thermodynamic/熱力学的性質 -- interfacial energies/界面エネルギー + active: true +- id: thermodynamic -- liquid crystal phase transition + term: thermodynamic/熱力学的性質 -- liquid crystal phase transition/液晶相転移温度 + active: true +- id: thermodynamic -- molar volume + term: thermodynamic/熱力学的性質 -- molar volume/モル体積 + active: true +- id: thermodynamic -- phase diagram + term: thermodynamic/熱力学的性質 -- phase diagram/相図 + active: true +- id: thermodynamic -- phase stability + term: thermodynamic/熱力学的性質 -- phase stability/相安定性 + active: true +- id: thermodynamic -- specific heat + term: thermodynamic/熱力学的性質 -- specific heat/比熱 + active: true +- id: thermodynamic -- superconductivity + term: thermodynamic/熱力学的性質 -- superconductivity/超伝導 + active: true +- id: thermodynamic -- surface energies + term: thermodynamic/熱力学的性質 -- surface energies/表面エネルギー + active: true +- id: thermodynamic -- melting temperature + term: |- + thermodynamic/熱力学的性質 -- temperature + melting temperature/融点 + active: true +- id: thermodynamic -- thermal conductivity + term: thermodynamic/熱力学的性質 -- thermal conductivity/熱伝導率 + active: true +- id: thermodynamic -- thermal decomposition temperature + term: thermodynamic/熱力学的性質 -- thermal decomposition temperature/熱分解温度 + active: true +- id: thermodynamic -- thermal expansion + term: thermodynamic/熱力学的性質 -- thermal expansion/熱膨張 + active: true +- id: toxicity + term: toxicity/毒性(toxicity) + active: true +- id: transport + term: transport/輸送 + active: true +- id: transport -- diffusivity + term: transport/輸送 -- diffusivity/拡散率 + active: true +- id: transport -- grain boundary diffusivity + term: transport/輸送 -- grain boundary diffusivity/粒界拡散率 + active: true +- id: transport -- interdiffusion + term: transport/輸送 -- interdiffusion/相互拡散 + active: true +- id: transport -- intrinsic diffusivity + term: transport/輸送 -- intrinsic diffusivity/固有拡散率(intrinsic diffusivity) + active: true +- id: transport -- mobilities + term: transport/輸送 -- mobilities/移動(mobility) + active: true +- id: transport -- surface diffusivity + term: transport/輸送 -- surface diffusivity/表面拡散率 + active: true +- id: transport -- tracer diffusivity + term: transport/輸送 -- tracer diffusivity/トレーサ拡散率 + active: true diff --git a/hyrax/config/authorities/relationships.yml b/hyrax/config/authorities/relationships.yml new file mode 100644 index 00000000..601ce6d3 --- /dev/null +++ b/hyrax/config/authorities/relationships.yml @@ -0,0 +1,112 @@ +terms: + - id: cites + term: cites + active: true + - id: isCitedBy + term: is cited by + active: true + - id: isSupplementTo + term: is supplement to + active: true + - id: isSupplementedBy + term: is supplemented by + active: true + - id: continues + term: continues + active: true + - id: isContinuedBy + term: is continued by + active: true + - id: hasMetadata + term: has metadata + active: true + - id: isMetadataFor + term: is metadata for + active: true + - id: isNewVersionOf + term: is new version of + active: true + - id: isPreviousVersionOf + term: is previous version of + active: true + - id: isPartOf + term: is part of + active: true + - id: hasPart + term: has part + active: true + - id: isReferencedBy + term: is referenced by + active: true + - id: references + term: references + active: true + - id: isDocumentedBy + term: is documented by + active: true + - id: documents + term: documents + active: true + - id: isCompiledBy + term: is compiled by + active: true + - id: compiles + term: compiles + active: true + - id: isVariantFormOf + term: is variant form of + active: true + - id: isOriginalFormOf + term: is original form of + active: true + - id: isIdenticalTo + term: is identical to + active: true + - id: isReviewedBy + term: is reviewed by + active: true + - id: reviews + term: reviews + active: true + - id: isDerivedFrom + term: is derived from + active: true + - id: isSourceOf + term: is source of + active: true + - id: isCommentOn + term: is comment on + active: true + - id: hasComment + term: has comment + active: true + - id: isReplyTo + term: is reply to + active: true + - id: hasReply + term: has reply + active: true + - id: basedOnData + term: based on data + active: true + - id: hasRelatedMaterial + term: has related material + active: true + - id: isBasedOn + term: is based on + active: true + - id: isBasisFor + term: is basis for + active: true + - id: requires + term: requires + active: true + - id: isRequiredBy + term: is required by + active: true + - id: hasParent + term: has parent + active: true + - id: isParentOf + term: is parent of + active: true diff --git a/hyrax/config/authorities/resource_types.yml b/hyrax/config/authorities/resource_types.yml index 69c22256..f3634b02 100644 --- a/hyrax/config/authorities/resource_types.yml +++ b/hyrax/config/authorities/resource_types.yml @@ -5,34 +5,22 @@ terms: term: Audio - id: Book term: Book - - id: Capstone Project - term: Capstone Project - id: Conference Proceeding term: Conference Proceeding - - id: Dataset - term: Dataset - id: Dissertation term: Dissertation - id: Image term: Image - id: Journal term: Journal - - id: Map or Cartographic Material - term: Map or Cartographic Material - - id: Masters Thesis - term: Masters Thesis - id: Part of Book term: Part of Book - id: Poster term: Poster - id: Presentation term: Presentation - - id: Project - term: Project - id: Report term: Report - - id: Research Paper - term: Research Paper - id: Software or Program Code term: Software or Program Code - id: Video diff --git a/hyrax/config/authorities/roles.yml b/hyrax/config/authorities/roles.yml new file mode 100644 index 00000000..e2927726 --- /dev/null +++ b/hyrax/config/authorities/roles.yml @@ -0,0 +1,22 @@ +terms: + - id: author + term: author/著者 + active: true + - id: editor + term: editor/編集者 + active: true + - id: translator + term: translator/翻訳者 + active: true + - id: data depositor + term: data depositor/データ記入者 + active: true + - id: data curator + term: data curator/データキュレーター + active: true + - id: contact person + term: contact person/連絡責任者 + active: true + - id: operator + term: operator/データ測定者・計算者 + active: true diff --git a/hyrax/config/authorities/structural_features.yml b/hyrax/config/authorities/structural_features.yml new file mode 100644 index 00000000..bdacd85b --- /dev/null +++ b/hyrax/config/authorities/structural_features.yml @@ -0,0 +1,271 @@ +terms: +- id: composites + term: composites/複合材料 + active: true +- id: composites -- biological or green + term: composites/複合材料 -- biological or green/生物学的またはグリーン + active: true +- id: composites -- fiber-reinforced + term: composites/複合材料 -- fiber-reinforced/繊維強化 + active: true +- id: composites -- metal-matrix + term: composites/複合材料 -- metal-matrix/金属マトリックス + active: true +- id: composites -- nanocomposites + term: composites/複合材料 -- nanocomposites/ナノコンポジット + active: true +- id: composites -- particle-reinforced + term: composites/複合材料 -- particle-reinforced/粒子強化 + active: true +- id: composites -- polymer-matrix + term: composites/複合材料 -- polymer-matrix/ポリマーマトリックス + active: true +- id: composites -- structural + term: composites/複合材料 -- structural/構造 + active: true +- id: defects + term: defects/欠陥 + active: true +- id: defects -- cracks + term: defects/欠陥 -- cracks/クラック + active: true +- id: defects -- crazing + term: defects/欠陥 -- crazing/ひび割れ(crazing) + active: true +- id: defects -- debonding + term: defects/欠陥 -- debonding/脱結合 + active: true +- id: defects -- disclinations + term: defects/欠陥 -- disclinations/回位 + active: true +- id: defects -- dislocations + term: defects/欠陥 -- dislocations/転位 + active: true +- id: defects -- inclusions + term: defects/欠陥 -- inclusions/内包物 + active: true +- id: defects -- interstitials + term: defects/欠陥 -- interstitials/インタースティシャル + active: true +- id: defects -- point defects + term: defects/欠陥 -- point defects/点欠陥 + active: true +- id: defects -- pores + term: defects/欠陥 -- pores/細孔(pore) + active: true +- id: defects -- vacancies + term: defects/欠陥 -- vacancies/空孔(vacancy) + active: true +- id: defects -- voids + term: defects/欠陥 -- voids/空隙(void) + active: true +- id: engineered structures + term: engineered structures/工学的構造 + active: true +- id: interfacial + term: interfacial/界面 + active: true +- id: interfacial -- grain boundaries + term: interfacial/界面 -- grain boundaries/粒界 + active: true +- id: interfacial -- interfacial surface area + term: interfacial/界面 -- interfacial surface area/表面・界面領域 + active: true +- id: interfacial -- magnetic domain walls + term: interfacial/界面 -- magnetic domain walls/磁壁 + active: true +- id: interfacial -- ordering boundaries + term: interfacial/界面 -- ordering boundaries/秩序境界(ordering boundary) + active: true +- id: interfacial -- phase boundaries + term: interfacial/界面 -- phase boundaries/相境界 + active: true +- id: interfacial -- stacking faults + term: interfacial/界面 -- stacking faults/積層欠陥 + active: true +- id: interfacial -- surfaces + term: interfacial/界面 -- surfaces/表面 + active: true +- id: interfacial -- twin boundaries + term: interfacial/界面 -- twin boundaries/双境界 + active: true +- id: microstructures + term: microstructures/微細構造(microstructure) + active: true +- id: microstructures -- cellular + term: microstructures/微細構造(microstructure) -- cellular/細胞 + active: true +- id: microstructures -- clustering + term: microstructures/微細構造(microstructure) -- clustering/クラスタリング + active: true +- id: microstructures -- compound + term: microstructures/微細構造(microstructure) -- compound/化合物 + active: true +- id: microstructures -- crystallinity + term: microstructures/微細構造(microstructure) -- crystallinity/結晶性 + active: true +- id: microstructures -- defect structures + term: microstructures/微細構造(microstructure) -- defect structures/欠陥構造 + active: true +- id: microstructures -- dendritic + term: microstructures/微細構造(microstructure) -- dendritic/樹枝状 + active: true +- id: microstructures -- dispersion + term: microstructures/微細構造(microstructure) -- dispersion/分散 + active: true +- id: microstructures -- eutectic + term: microstructures/微細構造(microstructure) -- eutectic/共晶 + active: true +- id: microstructures -- grains + term: microstructures/微細構造(microstructure) -- grains/粒 + active: true +- id: microstructures -- nanocrystalline + term: microstructures/微細構造(microstructure) -- nanocrystalline/ナノ結晶 + active: true +- id: microstructures -- particle distribution + term: microstructures/微細構造(microstructure) -- particle distribution/粒子分布 + active: true +- id: microstructures -- particle shape + term: microstructures/微細構造(microstructure) -- particle shape/粒子形状 + active: true +- id: microstructures -- polycrystalline + term: microstructures/微細構造(microstructure) -- polycrystalline/多結晶 + active: true +- id: microstructures -- polydispersity + term: microstructures/微細構造(microstructure) -- polydispersity/多分散性 + active: true +- id: microstructures -- porosity + term: microstructures/微細構造(microstructure) -- porosity/空隙率(porosity) + active: true +- id: microstructures -- precipitates + term: microstructures/微細構造(microstructure) -- precipitates/沈殿物(precipitate) + active: true +- id: microstructures -- quasicrystalline + term: microstructures/微細構造(microstructure) -- quasicrystalline/準結晶 + active: true +- id: microstructures -- single crystal + term: microstructures/微細構造(microstructure) -- single crystal/単結晶 + active: true +- id: microstructures -- twinned + term: microstructures/微細構造(microstructure) -- twinned/双晶 + active: true +- id: molecular structure + term: molecular structure/分子構造 + active: true +- id: molecular structure -- alternating copolymer + term: molecular structure/分子構造 -- alternating copolymer/交互共重合体 + active: true +- id: molecular structure -- block copolymer + term: molecular structure/分子構造 -- block copolymer/ブロック共重合体 + active: true +- id: molecular structure -- dendrimer + term: molecular structure/分子構造 -- dendrimer/デンドリマー + active: true +- id: molecular structure -- end-group composition + term: molecular structure/分子構造 -- end-group composition/末端基組成 + active: true +- id: molecular structure -- functionalization + term: molecular structure/分子構造 -- functionalization/機能化 + active: true +- id: molecular structure -- gradient copolymer + term: molecular structure/分子構造 -- gradient copolymer/グラジエントコポリマー + active: true +- id: molecular structure -- long-chain branching + term: molecular structure/分子構造 -- long-chain branching/長鎖分岐 + active: true +- id: molecular structure -- random copolymer + term: molecular structure/分子構造 -- random copolymer/ランダム共重合体 + active: true +- id: molecular structure -- short-chain branching + term: molecular structure/分子構造 -- short-chain branching/短鎖分岐 + active: true +- id: molecular structure -- surfactants + term: molecular structure/分子構造 -- surfactants/界面活性剤 + active: true +- id: molecular structure -- tacticity + term: molecular structure/分子構造 -- tacticity/立体規則性 + active: true +- id: morphologies + term: morphologies/形態 + active: true +- id: morphologies -- aligned + term: morphologies/形態 -- aligned/整列状態 + active: true +- id: morphologies -- amorphous + term: morphologies/形態 -- amorphous/アモルファス + active: true +- id: morphologies -- clusters + term: morphologies/形態 -- clusters/クラスタ + active: true +- id: morphologies -- complex fluids + term: morphologies/形態 -- complex fluids/複雑流体 + active: true +- id: morphologies -- glass + term: morphologies/形態 -- glass/ガラス + active: true +- id: morphologies -- layered + term: morphologies/形態 -- layered/層状 + active: true +- id: morphologies -- nanoparticles or nanotubes + term: morphologies/形態 -- nanoparticles or nanotubes/ナノ粒子_ナノチューブ + active: true +- id: morphologies -- one-dimensional + term: morphologies/形態 -- one-dimensional/1次元 + active: true +- id: morphologies -- open-framework + term: morphologies/形態 -- open-framework/オープンフレームワーク + active: true +- id: morphologies -- particles or colloids + term: morphologies/形態 -- particles or colloids/粒子_コロイド + active: true +- id: morphologies -- porous + term: morphologies/形態 -- porous/多孔質 + active: true +- id: morphologies -- quantum dots or wires + term: morphologies/形態 -- quantum dots or wires/量子ドット_ワイヤ + active: true +- id: morphologies -- random + term: morphologies/形態 -- random/ランダム + active: true +- id: morphologies -- semicrystalline + term: morphologies/形態 -- semicrystalline/半結晶質 + active: true +- id: morphologies -- thin film + term: morphologies/形態 -- thin film/薄膜 + active: true +- id: morphologies -- two-dimensional + term: morphologies/形態 -- two-dimensional/2次元 + active: true +- id: morphologies -- wires + term: morphologies/形態 -- wires/ワイヤー + active: true +- id: morphologies -- woven + term: morphologies/形態 -- woven/織物(woven) + active: true +- id: phases + term: phases/相 + active: true +- id: phases -- crystalline + term: phases/相 -- crystalline/結晶 + active: true +- id: phases -- disordered + term: phases/相 -- disordered/無秩序性 + active: true +- id: phases -- gas + term: phases/相 -- gas/ガス + active: true +- id: phases -- liquid + term: phases/相 -- liquid/液体 + active: true +- id: phases -- melt + term: phases/相 -- melt/溶融(melt) + active: true +- id: phases -- metastable + term: phases/相 -- metastable/準安定 + active: true +- id: phases -- nonequilibrium + term: phases/相 -- nonequilibrium/非平衡 + active: true +- id: phases -- ordered + term: phases/相 -- ordered/秩序性 + active: true diff --git a/hyrax/config/authorities/synthesis_and_processing.yml b/hyrax/config/authorities/synthesis_and_processing.yml new file mode 100644 index 00000000..5b6b0369 --- /dev/null +++ b/hyrax/config/authorities/synthesis_and_processing.yml @@ -0,0 +1,284 @@ +terms: +- id: annealing and homogenization + term: annealing and homogenization/アニーリング_均一化処理 + active: true +- id: annealing and homogenization -- aging + term: annealing and homogenization/アニーリング_均一化処理 -- aging/エージング + active: true +- id: annealing and homogenization -- homogenization + term: annealing and homogenization/アニーリング_均一化処理 -- homogenization/均質化 + active: true +- id: annealing and homogenization -- mechanical mixing + term: annealing and homogenization/アニーリング_均一化処理 -- mechanical mixing/機械的混合 + active: true +- id: annealing and homogenization -- melt mixing + term: annealing and homogenization/アニーリング_均一化処理 -- melt mixing/溶融混合 + active: true +- id: annealing and homogenization -- normalizing + term: annealing and homogenization/アニーリング_均一化処理 -- normalizing/焼きならし(焼準) + active: true +- id: annealing and homogenization -- recrystallization + term: annealing and homogenization/アニーリング_均一化処理 -- recrystallization/再結晶化 + active: true +- id: annealing and homogenization -- stress relieving + term: annealing and homogenization/アニーリング_均一化処理 -- stress relieving/応力緩和 + active: true +- id: annealing and homogenization -- tempering + term: annealing and homogenization/アニーリング_均一化処理 -- tempering/焼き戻し + active: true +- id: annealing and homogenization -- ultrasonication + term: annealing and homogenization/アニーリング_均一化処理 -- ultrasonication/超音波処理 + active: true +- id: casting + term: casting/鋳造 + active: true +- id: casting -- centrifugal casting + term: casting/鋳造 -- centrifugal casting/遠心鋳造 + active: true +- id: casting -- continuous casting + term: casting/鋳造 -- continuous casting/連続鋳造 + active: true +- id: casting -- die casting + term: casting/鋳造 -- die casting/ダイカスト + active: true +- id: casting -- investment casting + term: casting/鋳造 -- investment casting/インベストメント鋳造 + active: true +- id: casting -- sand castingslip + term: casting/鋳造 -- sand castingslip/砂キャスティングスリップ + active: true +- id: casting -- slip casting + term: casting/鋳造 -- slip casting/スリップキャスティング + active: true +- id: casting -- vacuum arc melting + term: casting/鋳造 -- vacuum arc melting/真空アーク溶解 + active: true +- id: deposition and coating + term: deposition and coating/蒸着_成膜 + active: true +- id: deposition and coating -- Langmuir-Blodgett film deposition + term: deposition and coating/蒸着_成膜 -- Langmuir-Blodgett film deposition/ラングミュア - + ブロジェット膜堆積 + active: true +- id: deposition and coating -- atomic layer deposition + term: deposition and coating/蒸着_成膜 -- atomic layer deposition/原子層堆積(ALD) + active: true +- id: deposition and coating -- carbon evaporation coating + term: deposition and coating/蒸着_成膜 -- carbon evaporation coating/炭素蒸発コーティング + active: true +- id: deposition and coating -- chemical vapor deposition + term: deposition and coating/蒸着_成膜 -- chemical vapor deposition/化学蒸着(CVD) + active: true +- id: deposition and coating -- electrodeposition + term: deposition and coating/蒸着_成膜 -- electrodeposition/電着 + active: true +- id: deposition and coating -- electron beam deposition + term: deposition and coating/蒸着_成膜 -- electron beam deposition/電子ビーム蒸着 + active: true +- id: deposition and coating -- evaporation + term: deposition and coating/蒸着_成膜 -- evaporation/蒸発(evaporation) + active: true +- id: deposition and coating -- gold-sputter coating + term: deposition and coating/蒸着_成膜 -- gold-sputter coating/金スパッタコーティング + active: true +- id: deposition and coating -- ink-jet deposition + term: deposition and coating/蒸着_成膜 -- ink-jet deposition/インクジェット堆積 + active: true +- id: deposition and coating -- ion beam deposition + term: deposition and coating/蒸着_成膜 -- ion beam deposition/イオンビーム蒸着 + active: true +- id: deposition and coating -- physical vapor deposition + term: deposition and coating/蒸着_成膜 -- physical vapor deposition/物理蒸着 + active: true +- id: deposition and coating -- plasma spraying + term: deposition and coating/蒸着_成膜 -- plasma spraying/プラズマ溶射 + active: true +- id: deposition and coating -- pulsed laser deposition + term: deposition and coating/蒸着_成膜 -- pulsed laser deposition/パルスレーザ堆積 + active: true +- id: deposition and coating -- spin coating + term: deposition and coating/蒸着_成膜 -- spin coating/スピンコーティング + active: true +- id: deposition and coating -- splatter + term: deposition and coating/蒸着_成膜 -- splatter/飛散(splatter) + active: true +- id: deposition and coating -- sputter coating + term: deposition and coating/蒸着_成膜 -- sputter coating/スパッタコーティング + active: true +- id: forming + term: forming/成形 + active: true +- id: forming -- cold rolling + term: forming/成形 -- cold rolling/冷間圧延 + active: true +- id: forming -- drawing + term: forming/成形 -- drawing/引抜(drawing) + active: true +- id: forming -- extrusion + term: forming/成形 -- extrusion/押出 + active: true +- id: forming -- forging + term: forming/成形 -- forging/鍛造 + active: true +- id: forming -- hot pressing + term: forming/成形 -- hot pressing/ホットプレス + active: true +- id: forming -- hot rolling + term: forming/成形 -- hot rolling/熱間圧延 + active: true +- id: forming -- milling + term: forming/成形 -- milling/粉砕 + active: true +- id: forming -- molding + term: forming/成形 -- molding/成形 + active: true +- id: fractionation + term: fractionation/分別(fractionation) + active: true +- id: mechanical and surface + term: mechanical and surface/機械的_表面 + active: true +- id: mechanical and surface -- doctor blade or blade coating + term: mechanical and surface/機械的_表面 -- doctor blade or blade coating/ドクターブレード_ブレードコーティング + active: true +- id: mechanical and surface -- focused ion beam + term: mechanical and surface/機械的_表面 -- focused ion beam/集束イオンビーム + active: true +- id: mechanical and surface -- joining + term: mechanical and surface/機械的_表面 -- joining/接合 + active: true +- id: mechanical and surface -- lithography + term: mechanical and surface/機械的_表面 -- lithography/リソグラフィー + active: true +- id: mechanical and surface -- polishing + term: mechanical and surface/機械的_表面 -- polishing/研磨 + active: true +- id: mechanical and surface -- sectioning + term: mechanical and surface/機械的_表面 -- sectioning/切断 + active: true +- id: mechanical and surface -- thermal plasma processing + term: mechanical and surface/機械的_表面 -- thermal plasma processing/熱プラズマ処理 + active: true +- id: powder processing + term: powder processing/粉末処理 + active: true +- id: powder processing -- atomization + term: powder processing/粉末処理 -- atomization/噴霧 + active: true +- id: powder processing -- ball milling + term: powder processing/粉末処理 -- ball milling/ボールミル + active: true +- id: powder processing -- centrifugal disintegration + term: powder processing/粉末処理 -- centrifugal disintegration/遠心分離 + active: true +- id: powder processing -- hot pressing + term: powder processing/粉末処理 -- hot pressing/ホットプレス + active: true +- id: powder processing -- sintering + term: powder processing/粉末処理 -- sintering/焼結 + active: true +- id: powder processing -- sponge iron process + term: powder processing/粉末処理 -- sponge iron process/スポンジ鉄プロセス + active: true +- id: quenching + term: quenching/焼入れ(quenching) + active: true +- id: quenching -- air cooled _ quench + term: quenching/焼入れ(quenching) -- air cooled _ quench/空冷_急冷 + active: true +- id: quenching -- brine quench + term: quenching/焼入れ(quenching) -- brine quench/ブラインクエンチ + active: true +- id: quenching -- furnace cooled + term: quenching/焼入れ(quenching) -- furnace cooled/炉冷却 + active: true +- id: quenching -- gas cooled + term: quenching/焼入れ(quenching) -- gas cooled/ガス冷却 + active: true +- id: quenching -- ice quench + term: quenching/焼入れ(quenching) -- ice quench/氷クエンチ + active: true +- id: quenching -- liquid nitrogen quench + term: quenching/焼入れ(quenching) -- liquid nitrogen quench/液体窒素急冷 + active: true +- id: quenching -- oil quench + term: quenching/焼入れ(quenching) -- oil quench/油(oil)クエンチ + active: true +- id: quenching -- water quench + term: quenching/焼入れ(quenching) -- water quench/水クエンチ + active: true +- id: reactive + term: reactive/反応 + active: true +- id: reactive -- addition polymerization + term: reactive/反応 -- addition polymerization/付加重合 + active: true +- id: reactive -- condensation polymerization + term: reactive/反応 -- condensation polymerization/縮合重合 + active: true +- id: reactive -- curing + term: reactive/反応 -- curing/硬化する + active: true +- id: reactive -- dissolving _ etching + term: reactive/反応 -- dissolving _ etching/溶解_エッチング + active: true +- id: reactive -- drying + term: reactive/反応 -- drying/乾燥 + active: true +- id: reactive -- in-situ polymerization + term: reactive/反応 -- in-situ polymerization/in-situ重合 + active: true +- id: reactive -- post-polymerization modification + term: reactive/反応 -- post-polymerization modification/後重合改質 + active: true +- id: reactive -- reductive roasting + term: reactive/反応 -- reductive roasting/還元焙煎 + active: true +- id: reactive -- solution processing + term: reactive/反応 -- solution processing/ソリューション処理 + active: true +- id: reactive -- solvent casting + term: reactive/反応 -- solvent casting/ソルベントキャスティング + active: true +- id: self-assembly + term: self-assembly/自己組織化 + active: true +- id: self-assembly -- micelle formation + term: self-assembly/自己組織化 -- micelle formation/ミセル形成 + active: true +- id: self-assembly -- monolayer formation + term: self-assembly/自己組織化 -- monolayer formation/単層形成 + active: true +- id: self-assembly -- self-assembly-assisted grafting + term: self-assembly/自己組織化 -- self-assembly-assisted grafting/自己組織化グラフト + active: true +- id: solidification + term: solidification/固化(solidification) + active: true +- id: solidification -- crystallization + term: solidification/固化(solidification) -- crystallization/結晶化温度 + active: true +- id: solidification -- directional solidification + term: solidification/固化(solidification) -- directional solidification/指向性凝固 + active: true +- id: solidification -- injection molding + term: solidification/固化(solidification) -- injection molding/射出成形 + active: true +- id: solidification -- precipitation + term: solidification/固化(solidification) -- precipitation/沈殿物(precipitate) + active: true +- id: solidification -- rapid solidification + term: solidification/固化(solidification) -- rapid solidification/急速凝固 + active: true +- id: solidification -- seeded solidification + term: solidification/固化(solidification) -- seeded solidification/播種凝固 + active: true +- id: solidification -- single crystal solidification + term: solidification/固化(solidification) -- single crystal solidification/単結晶凝固 + active: true +- id: solidification -- vacuum molding + term: solidification/固化(solidification) -- vacuum molding/真空成形 + active: true +- id: solidification -- zone refining + term: solidification/固化(solidification) -- zone refining/ゾーン精製 + active: true diff --git a/hyrax/config/blacklight.yml b/hyrax/config/blacklight.yml index 9ea32544..5357d8fb 100644 --- a/hyrax/config/blacklight.yml +++ b/hyrax/config/blacklight.yml @@ -1,9 +1,11 @@ +# NB: the URLs in this file should match those in solr.yml + development: adapter: solr - url: <%= ENV['SOLR_URL'] || "http://127.0.0.1:#{ENV.fetch('SOLR_DEVELOPMENT_PORT', 8983)}/solr/hydra-development" %> + url: <%= ENV['SOLR_URL_SCHEME'] || 'http' %>://<%= ENV['SOLR_HOST'] || '127.0.0.1' %>:<%= ENV['SOLR_PORT'] || '8983' %>/solr/hydra-development test: &test adapter: solr - url: <%= ENV['SOLR_URL'] || "http://127.0.0.1:#{ENV.fetch('SOLR_TEST_PORT', 8985)}/solr/hydra-test" %> + url: <%= ENV['SOLR_URL_SCHEME'] || 'http' %>://<%= ENV['SOLR_HOST'] || '127.0.0.1' %>:<%= ENV['SOLR_TEST_PORT'] || '8985' %>/solr/hydra-test production: adapter: solr - url: <%= ENV['SOLR_URL'] || "http://127.0.0.1:8983/solr/blacklight-core" %> + url: <%= ENV['SOLR_URL_SCHEME'] || 'http' %>://<%= ENV['SOLR_HOST'] || 'solr' %>:<%= ENV['SOLR_PORT'] || '8983' %>/solr/hyrax_production diff --git a/hyrax/config/browse_everything_providers.yml b/hyrax/config/browse_everything_providers.yml new file mode 100644 index 00000000..addf06c6 --- /dev/null +++ b/hyrax/config/browse_everything_providers.yml @@ -0,0 +1,30 @@ +# +# To make browse-everything aware of a provider, uncomment the info for that provider and add your API key information. +# The file_system provider can be a path to any directory on the server where your application is running. +# +--- +google_drive: + :client_id: <%= ENV['GOOGLE_DRIVE_CLIENT_ID'] %> + :client_secret: <%= ENV['GOOGLE_DRIVE_CLIENT_SECRET'] %> +box: + :client_id: <%= ENV['BOX_CLIENT_ID'] %> + :client_secret: <%= ENV['BOX_CLIENT_SECRET'] %> + +# file_system: +# :home: "" +# dropbox: +# :app_key: YOUR_DROPBOX_APP_KEY +# :app_secret: YOUR_DROPBOX_APP_SECRET +# box: +# :client_id: YOUR_BOX_CLIENT_ID +# :client_secret: YOUR_BOX_CLIENT_SECRET +# google_drive: +# :client_id: YOUR_GOOGLE_API_CLIENT_ID +# :client_secret: YOUR_GOOGLE_API_CLIENT_SECRET +# s3: +# :bucket: YOUR_AWS_S3_BUCKET +# :response_type: :signed_url # set to :public_url for public urls or :s3_uri for an s3://BUCKET/KEY uri +# :app_key: YOUR_AWS_S3_KEY # :app_key, :app_secret, and :region can be specified +# :app_secret: YOUR_AWS_S3_SECRET # explicitly here, or left out to use system-configured +# :region: YOUR_AWS_S3_REGION # defaults. +# See https://aws.amazon.com/blogs/security/a-new-and-standardized-way-to-manage-credentials-in-the-aws-sdks/ diff --git a/hyrax/config/cable.yml b/hyrax/config/cable.yml index 73739d63..b4ec06e7 100644 --- a/hyrax/config/cable.yml +++ b/hyrax/config/cable.yml @@ -1,10 +1,12 @@ development: adapter: redis - url: redis://localhost:6379 + url: redis://<%= ENV['REDIS_HOST'] || 'localhost' %>:<%= ENV['REDIS_PORT'] || '6379' %>/1 + channel_prefix: hyrax_development test: adapter: async production: adapter: redis - url: redis://localhost:6379/1 + url: redis://<%= ENV['REDIS_HOST'] || 'redis' %>:<%= ENV['REDIS_PORT'] || '6379' %>/1 + channel_prefix: hyrax_production diff --git a/hyrax/config/cucumber.yml b/hyrax/config/cucumber.yml new file mode 100644 index 00000000..5aa9c13b --- /dev/null +++ b/hyrax/config/cucumber.yml @@ -0,0 +1,9 @@ +<% +rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" +rerun = rerun.strip.gsub /\s/, ' ' +rerun_opts = rerun.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" +std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags 'not @wip'" +%> +default: <%= std_opts %> features +wip: --tags @wip:3 --wip features +rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags 'not @wip' diff --git a/hyrax/config/database.yml b/hyrax/config/database.yml index 1c1a37ca..baa9b7f0 100644 --- a/hyrax/config/database.yml +++ b/hyrax/config/database.yml @@ -1,25 +1,26 @@ -# SQLite version 3.x -# gem install sqlite3 -# -# Ensure the SQLite 3 gem is defined in your Gemfile -# gem 'sqlite3' -# default: &default - adapter: sqlite3 - pool: 5 + adapter: postgresql + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 + encoding: unicode + host: <%= ENV['POSTGRES_HOST_APP'] || 'db' %> + port: <%= ENV['POSTGRES_PORT'] || '5432' %> + username: <%= ENV['POSTGRES_USER'] || 'postgres' %> + password: <%= ENV['POSTGRES_PASSWORD'] || 'password' %> development: - <<: *default + adapter: sqlite3 database: db/development.sqlite3 + pool: 5 + timeout: 5000 -# Warning: The database defined as "test" will be erased and -# re-generated from your development database when you run "rake". -# Do not set this db to the same as development or production. test: - <<: *default + adapter: sqlite3 database: db/test.sqlite3 + pool: 5 + timeout: 5000 production: <<: *default - database: db/production.sqlite3 + database: <%= ENV['POSTGRES_DB_APP'] || 'hyrax_production' %> + pool: 50 diff --git a/hyrax/config/environments/development.rb b/hyrax/config/environments/development.rb index 6f719704..79b60d93 100644 --- a/hyrax/config/environments/development.rb +++ b/hyrax/config/environments/development.rb @@ -18,7 +18,7 @@ config.cache_store = :memory_store config.public_file_server.headers = { - 'Cache-Control' => 'public, max-age=172800' + 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}" } else config.action_controller.perform_caching = false @@ -26,6 +26,9 @@ config.cache_store = :null_store end + # Use Sidekiq to process background jobs + config.active_job.queue_adapter = :sidekiq + # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false @@ -51,4 +54,10 @@ # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end end diff --git a/hyrax/config/environments/production.rb b/hyrax/config/environments/production.rb index 8961da20..cbfcd940 100644 --- a/hyrax/config/environments/production.rb +++ b/hyrax/config/environments/production.rb @@ -11,12 +11,27 @@ config.eager_load = true # Full error reports are disabled and caching is turned on. + # To display stack traces in production, you want + # config.consider_all_requests_local = true + # To hide stack traces in production, set this to false. config.consider_all_requests_local = false config.action_controller.perform_caching = true + # Use Sidekiq to process background jobs + config.active_job.queue_adapter = :sidekiq + + # Attempt to read encrypted secrets from `config/secrets.yml.enc`. + # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or + # `config/secrets.yml.key`. + # config.read_encrypted_secrets = true + # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. - config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? + if ENV['RAILS_SERVE_STATIC_FILES'].present? + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'] + else + config.public_file_server.enabled = true + end # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier @@ -40,15 +55,34 @@ # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true + if ENV["RAILS_FORCE_SSL"].present? && (ENV["RAILS_FORCE_SSL"].to_s.downcase == 'false') then + config.force_ssl = false + else + config.force_ssl = true #default if nothing specified is more secure. + Rails.application.routes.default_url_options = {protocol: 'https', host: ENV['MDR_HOST']} + end - # Use the lowest log level to ensure availability of diagnostic information + # Use the lowest log level (:debug) to ensure availability of diagnostic information # when problems arise. - config.log_level = :debug + config.log_level = :info # Prepend all log lines with the following tags. config.log_tags = [ :request_id ] + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require 'syslog/logger' + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -68,19 +102,14 @@ # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify - # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new - - # Use a different logger for distributed setups. - # require 'syslog/logger' - # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') - - if ENV["RAILS_LOG_TO_STDOUT"].present? - logger = ActiveSupport::Logger.new(STDOUT) - logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) - end - # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + config.action_mailer.perform_deliveries = true + config.action_mailer.delivery_method = :smtp + config.action_mailer.smtp_settings = { + address: ENV['SMTP_HOST'], + port: ENV['SMTP_PORT'], + enable_starttls_auto: false + } end diff --git a/hyrax/config/environments/test.rb b/hyrax/config/environments/test.rb index 30587ef6..a93969eb 100644 --- a/hyrax/config/environments/test.rb +++ b/hyrax/config/environments/test.rb @@ -15,7 +15,7 @@ # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true config.public_file_server.headers = { - 'Cache-Control' => 'public, max-age=3600' + 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}" } # Show full error reports and disable caching. @@ -39,4 +39,9 @@ # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + + # Don't use redis for storing queued jobs when running tests + config.active_job.queue_adapter = :test + + Rails.application.routes.default_url_options = {protocol: 'http', host: 'localhost'} end diff --git a/hyrax/config/fcrepo_wrapper_test.yml b/hyrax/config/fcrepo_wrapper_test.yml index 77f79a6e..75397920 100644 --- a/hyrax/config/fcrepo_wrapper_test.yml +++ b/hyrax/config/fcrepo_wrapper_test.yml @@ -1,4 +1,7 @@ -#config/fcrepo_wrapper_test.yml.sample port: 8986 +verbose: false +version: '4.7.3' # NB: ideally this should match the version in docker-compose.yml +instance_dir: 'tmp/fcrepo4-test' +fcrepo_home_dir: 'tmp/fcrepo4-test/home' enable_jms: false -fcrepo_home_dir: tmp/fcrepo4-test-data +download_dir: 'tmp' diff --git a/hyrax/config/fedora.yml b/hyrax/config/fedora.yml index 10c488e1..bdebde7c 100644 --- a/hyrax/config/fedora.yml +++ b/hyrax/config/fedora.yml @@ -1,15 +1,15 @@ development: user: fedoraAdmin password: fedoraAdmin - url: http://127.0.0.1:<%= ENV['FCREPO_DEVELOPMENT_PORT'] || 8984 %>/rest + url: <%= ENV['FEDORA_URL_SCHEME'] || 'http' %>://<%= ENV['FEDORA_HOST'] || 'localhost' %>:<%= ENV['FCREPO_DEVELOPMENT_PORT'] || 8984 %>/rest base_path: /dev test: user: fedoraAdmin password: fedoraAdmin - url: http://127.0.0.1:<%= ENV['FCREPO_TEST_PORT'] || 8986 %>/rest + url: <%= ENV['FEDORA_URL_SCHEME'] || 'http' %>://<%= ENV['FEDORA_HOST'] || 'localhost' %>:<%= ENV['FEDORA_TEST_PORT'] || 8986 %>/rest base_path: /test production: user: fedoraAdmin password: fedoraAdmin - url: http://127.0.0.1:8983/fedora/rest - base_path: /prod + url: <%= ENV['FEDORA_URL_SCHEME'] || 'http' %>://<%= ENV['FEDORA_HOST'] || 'fcrepo' %>:<%= ENV['FEDORA_PORT'] || '8080' %>/fcrepo/rest + base_path: /hyrax_production diff --git a/hyrax/config/initializers/assets.rb b/hyrax/config/initializers/assets.rb index 01ef3e66..121a05c1 100644 --- a/hyrax/config/initializers/assets.rb +++ b/hyrax/config/initializers/assets.rb @@ -3,8 +3,10 @@ # Version of your assets, change this if you want to expire all your assets. Rails.application.config.assets.version = '1.0' -# Add additional assets to the asset load path +# Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. diff --git a/hyrax/config/initializers/citation_formatters.rb b/hyrax/config/initializers/citation_formatters.rb new file mode 100644 index 00000000..6c8bf0c6 --- /dev/null +++ b/hyrax/config/initializers/citation_formatters.rb @@ -0,0 +1,2 @@ +# prevent errors if no authors have been specified +Hyrax::CitationsBehaviors::Formatters::ApaFormatter.prepend Hyrax::CitationsBehaviors::Formatters::AuthorsListApa \ No newline at end of file diff --git a/hyrax/config/initializers/devise.rb b/hyrax/config/initializers/devise.rb index 14961e06..852da1f5 100644 --- a/hyrax/config/initializers/devise.rb +++ b/hyrax/config/initializers/devise.rb @@ -3,13 +3,26 @@ # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| + # ==> LDAP Configuration + # config.ldap_logger = true + config.ldap_create_user = true + # config.ldap_update_password = true + # config.ldap_config = "#{Rails.root}/config/ldap.yml" + # config.ldap_check_group_membership = false + # config.ldap_check_group_membership_without_admin = false + # config.ldap_check_attributes = false + # config.ldap_check_attributes_presence = false + # config.ldap_use_admin_to_bind = false + # config.ldap_ad_group_check = false + # The secret key used by Devise. Devise uses this key to generate # random tokens. Changing this key will render invalid all existing # confirmation, reset password and unlock tokens in the database. # Devise will use the `secret_key_base` as its `secret_key` # by default. You can change it below and use your own secret key. # config.secret_key = 'fe1af726ce5970b2cd7524a5085c424ab044f85c9634ca3fbe67702897af8ac218dcf94b13ec65912f87616ee0f07920a3a3e62bdaf2dd507701fe7deee8acaa' - + config.secret_key = ENV['DEVISE_SECRET_KEY'] || 'e420455a75122871256bbc94a75c12b0c4d8010a93c0a05b6237aa3d4e7da28720410158c62fb91ac1d2c95b36da2ae63fe67991012183d40f3bf5edbc2c8a28' + # ==> Controller configuration # Configure the parent class to the devise controllers. # config.parent_controller = 'DeviseController' @@ -18,7 +31,7 @@ # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. - config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' + config.mailer_sender = ENV['USER_MANAGEMENT_EMAIL_FROM_ADDRESS'] || 'please-change-me-at-config-initializers-devise@example.com' # Configure the class responsible to send e-mails. # config.mailer = 'Devise::Mailer' @@ -40,7 +53,7 @@ # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. - # config.authentication_keys = [:email] + config.authentication_keys = [:username] # Configure parameters from the request object used for authentication. Each entry # given should be a request method and it will automatically be passed to the @@ -52,12 +65,12 @@ # Configure which authentication keys should be case-insensitive. # These keys will be downcased upon creating or modifying a user and when used # to authenticate or find a user. Default is :email. - config.case_insensitive_keys = [:email] + config.case_insensitive_keys = [:username] # Configure which authentication keys should have whitespace stripped. # These keys will have whitespace before and after removed upon creating or # modifying a user and when used to authenticate or find a user. Default is :email. - config.strip_whitespace_keys = [:email] + config.strip_whitespace_keys = [:username] # Tell if authentication through request.params is enabled. True by default. # It can be set to an array that will enable params authentication only for the @@ -145,7 +158,7 @@ config.reconfirmable = true # Defines which key will be used when confirming an account - # config.confirmation_keys = [:email] + config.confirmation_keys = [:username] # ==> Configuration for :rememberable # The time the user will be remembered without asking for credentials again. @@ -179,24 +192,24 @@ # Defines which strategy will be used to lock an account. # :failed_attempts = Locks an account after a number of failed attempts to sign in. # :none = No lock strategy. You should handle locking by yourself. - # config.lock_strategy = :failed_attempts + config.lock_strategy = :failed_attempts # Defines which key will be used when locking and unlocking an account - # config.unlock_keys = [:email] + config.unlock_keys = [:username] # Defines which strategy will be used to unlock an account. # :email = Sends an unlock link to the user email # :time = Re-enables login after a certain amount of time (see :unlock_in below) # :both = Enables both strategies # :none = No unlock strategy. You should handle unlocking by yourself. - # config.unlock_strategy = :both + config.unlock_strategy = :time # Number of authentication tries before locking an account if lock_strategy # is failed attempts. - # config.maximum_attempts = 20 + config.maximum_attempts = 20 # Time interval to unlock the account if :time is enabled as unlock_strategy. - # config.unlock_in = 1.hour + config.unlock_in = 1.hour # Warn on the last attempt before the account is locked. # config.last_attempt_warning = true @@ -204,7 +217,7 @@ # ==> Configuration for :recoverable # # Defines which key will be used when recovering the password for an account - # config.reset_password_keys = [:email] + config.reset_password_keys = [:username] # Time interval you can reset your password with a reset password key. # Don't put a too small interval or your users won't have the time to @@ -262,10 +275,10 @@ # If you want to use other strategies, that are not supported by Devise, or # change the failure app, you can configure them inside the config.warden block. # - # config.warden do |manager| - # manager.intercept_401 = false - # manager.default_strategies(scope: :user).unshift :some_external_strategy - # end + Warden::Manager.after_authentication do |user,auth,opts| + # call the service to update the user's attributes (used for authorisation) after authentication + UserAuthorisationService.new(user).update_attributes + end # ==> Mountable engine configurations # When using Devise inside an engine, let's call it `MyEngine`, and this engine @@ -280,4 +293,67 @@ # When using OmniAuth, Devise cannot automatically set OmniAuth path, # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' + + # CAS (Central Authentication Service) setup + config.cas_base_url = ENV['CAS_BASE_URL'] || 'https://cas.nims.go.jp/' + + # you can override these if you need to, but cas_base_url is usually enough + # config.cas_login_url = "https://cas.myorganization.com/login" + # config.cas_logout_url = "https://cas.myorganization.com/logout" + # config.cas_validate_url = "https://cas.myorganization.com/serviceValidate" + if ENV['CAS_VALIDATE_URL'].present? + config.cas_validate_url = ENV['CAS_VALIDATE_URL'] + end + + # The CAS specification allows for the passing of a follow URL to be displayed when + # a user logs out on the CAS server. RubyCAS-Server also supports redirecting to a + # URL via the destination param. Set either of these urls and specify either nil, + # 'destination' or 'follow' as the logout_url_param. If the urls are blank but + # logout_url_param is set, a default will be detected for the service. + config.cas_destination_url = ENV['CAS_DESTINATION_URL'] + # config.cas_follow_url = 'https://cas.myorganization.com' + # config.cas_logout_url_param = nil + + # You can specify the name of the destination argument with the following option. + # e.g. the following option will change it from 'destination' to 'url' + # config.cas_destination_logout_param_name = 'url' + + # NB: these two parameters are necessary for single-sign-out to work correctly on the NIMS CAS server (Apereo CAS 6) + config.cas_logout_url_param = 'destination' + config.cas_destination_logout_param_name = 'service' + + # By default, devise_cas_authenticatable will create users. If you would rather + # require user records to already exist locally before they can authenticate via + # CAS, uncomment the following line. + # config.cas_create_user = false + + # You can enable Single Sign Out, which by default is disabled. + config.cas_enable_single_sign_out = true + + # If you don't want to use the username returned from your CAS server as the unique + # identifier, but some other field passed in cas_extra_attributes, you can specify + # the field name here. + # config.cas_user_identifier = nil + + # If you want to use the Devise Timeoutable module with single sign out, + # uncommenting this will redirect timeouts to the logout url, so that the CAS can + # take care of signing out the other serviced applocations. Note that each + # application manages timeouts independently, so one application timing out will + # kill the session on all applications serviced by the CAS. + # config.warden do |manager| + # manager.failure_app = DeviseCasAuthenticatable::SingleSignOut::WardenFailureApp + # end + + # You can also set another single sign out strategy so that you won't be attached to rails_cache. + # Be aware that to do so you also need to set the session_store. + # Example for setting redis_cache. + # There are some gems the help with it. One of them is called redis-rails and it can easily be set like this: + # Rails.application.config.session_store :redis_store, servers: ["redis://localhost:6379/0/session"] + # This is specially useful when you need to share session id accross apps (i.e. in a distributed environment) + # config.cas_single_sign_out_mapping_strategy = :redis_cache + + # If you need to specify some extra configs for rubycas-client, you can do this via: + # config.cas_client_config_options = { + # logger: Rails.logger + # } end diff --git a/hyrax/config/initializers/errbit.rb b/hyrax/config/initializers/errbit.rb new file mode 100644 index 00000000..a046220e --- /dev/null +++ b/hyrax/config/initializers/errbit.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +if Rails.env == 'production' + Airbrake.configure do |config| + # setting for the rails app + config.environment = Rails.env + config.ignore_environments = %w[development test] + # ignore production if the environment variables aren't set + config.ignore_environments << 'production' if ENV.fetch('AIRBRAKE_HOST', nil).blank? && + ENV.fetch('AIRBRAKE_PROJECT_ID', nil).blank? && + ENV.fetch('AIRBRAKE_PROJECT_KEY', nil).blank? + config.host = ENV['AIRBRAKE_HOST'] + config.project_id = ENV['AIRBRAKE_PROJECT_ID'] + config.project_key = ENV['AIRBRAKE_PROJECT_KEY'] + end +elsif defined?(Airbrake) + # disable Airbrake if the env vars are not present + puts 'Disabling Airbrake because the required env vars are not set' + Airbrake.configure do |c| + c.environment = Rails.env + c.ignore_environments = %w(development test production) + end +end diff --git a/hyrax/config/initializers/file_set_actor_override.rb b/hyrax/config/initializers/file_set_actor_override.rb new file mode 100644 index 00000000..499313e9 --- /dev/null +++ b/hyrax/config/initializers/file_set_actor_override.rb @@ -0,0 +1,17 @@ +# Override Hyrax 2.6 to support Japanese characters in filenames +# Use Addressable::URI.unencode rather than Addressable::URI.parse +# PR to Hyrax 3.x https://github.com/samvera/hyrax/pull/4172 +Hyrax::Actors::FileSetActor.class_eval do + def label_for(file) + if file.is_a?(Hyrax::UploadedFile) # filename not present for uncached remote file! + file.uploader.filename.present? ? file.uploader.filename : File.basename(Addressable::URI.unencode(file.file_url)) + elsif file.respond_to?(:original_name) # e.g. Hydra::Derivatives::IoDecorator + file.original_name + elsif file_set.import_url.present? + # This path is taken when file is a Tempfile (e.g. from ImportUrlJob) + File.basename(Addressable::URI.unencode(file.file_url)) + else + File.basename(file) + end + end +end \ No newline at end of file diff --git a/hyrax/config/initializers/file_set_derivatives_service_override.rb b/hyrax/config/initializers/file_set_derivatives_service_override.rb new file mode 100644 index 00000000..febc9cc2 --- /dev/null +++ b/hyrax/config/initializers/file_set_derivatives_service_override.rb @@ -0,0 +1,16 @@ +# Override Hyrax 2.6 to skip thumbnail creation for text files +Hyrax::FileSetDerivativesService.class_eval do + def create_office_document_derivatives(filename) + # Don't create thumbnails for 'text/plain','text/csv','text/tab-separated-values','text/rtf' + unless file_set.text? + Hydra::Derivatives::DocumentDerivatives.create(filename, + outputs: [{ + label: :thumbnail, format: 'jpg', + size: '200x150>', + url: derivative_url('thumbnail'), + layer: 0 + }]) + end + extract_full_text(filename, uri) + end +end diff --git a/hyrax/config/initializers/hyrax.rb b/hyrax/config/initializers/hyrax.rb index 333687f0..8f4ec60d 100644 --- a/hyrax/config/initializers/hyrax.rb +++ b/hyrax/config/initializers/hyrax.rb @@ -1,6 +1,12 @@ Hyrax.config do |config| # Injected via `rails g hyrax:work Work` config.register_curation_concern :work + # Injected via `rails g hyrax:work Dataset` + config.register_curation_concern :dataset + # Injected via `rails g hyrax:work Publication` + config.register_curation_concern :publication + # Injected via `rails g hyrax:work Image` + config.register_curation_concern :image # Register roles that are expected by your implementation. # @see Hyrax::RoleRegistry for additional details. # @note there are magical roles as defined in Hyrax::RoleRegistry::MAGIC_ROLES @@ -24,31 +30,34 @@ # config.rendering_predicate = ::RDF::DC.hasFormat # Email recipient of messages sent via the contact form - # config.contact_email = "repo-admin@example.org" + config.contact_email = ENV['CONTACT_FORM_RECIPIENT_EMAIL'] || "repo-admin@example.org" # Text prefacing the subject entered in the contact form - # config.subject_prefix = "Contact form:" + config.subject_prefix = ENV['CONTACT_FORM_SUBJECT_PREFIX'] || "Hyrax Contact form:" # How many notifications should be displayed on the dashboard # config.max_notifications_for_dashboard = 5 + # How often clients should poll for notifications + # config.notifications_update_poll_interval = 30.seconds + # How frequently should a file be fixity checked # config.max_days_between_fixity_checks = 7 # Options to control the file uploader - # config.uploader = { - # limitConcurrentUploads: 6, - # maxNumberOfFiles: 100, - # maxFileSize: 500.megabytes - # } + config.uploader = { + limitConcurrentUploads: 6, + maxNumberOfFiles: 100, + maxFileSize: 105.megabytes + } # Enable displaying usage statistics in the UI # Defaults to false # Requires a Google Analytics id and OAuth2 keyfile. See README for more info - # config.analytics = false + config.analytics = ENV['GOOGLE_ANALYTICS_ID'].present? # Google Analytics tracking ID to gather usage statistics - # config.google_analytics_id = 'UA-99999999-1' + config.google_analytics_id = ENV['GOOGLE_ANALYTICS_ID'] || 'UA-99999999-1' # Date you wish to start collecting Google Analytic statistics for # Leaving it blank will set the start date to when ever the file was uploaded by @@ -57,7 +66,7 @@ # Enables a link to the citations page for a work # Default is false - # config.citations = false + config.citations = true # Where to store tempfiles, leave blank for the system temp directory (e.g. /tmp) # config.temp_file_base = '/home/developer1' @@ -66,26 +75,30 @@ # config.persistent_hostpath = 'http://localhost/files/' # If you have ffmpeg installed and want to transcode audio and video set to true - # config.enable_ffmpeg = false + config.enable_ffmpeg = true # Hyrax uses NOIDs for files and collections instead of Fedora UUIDs # where NOID = 10-character string and UUID = 32-character string w/ hyphens # config.enable_noids = true - # Template for your repository's NOID IDs - # config.noid_template = ".reeddeeddk" + # In a test environment, use the file-based NOID generator to avoid problems with the tables being wiped between tests + if ENV['RAILS_ENV'] == 'test' + puts 'Using file-based NOIDs for tests' + # Template for your repository's NOID IDs + config.noid_template = "test-.zdddd" - # Use the database-backed minter class - # config.noid_minter_class = Noid::Rails::Minter::Db + # Use the database-backed minter class + config.noid_minter_class = Noid::Rails::Minter::File - # Store identifier minter's state in a file for later replayability - # config.minter_statefile = '/tmp/minter-state' + # Store identifier minter's state in a file for later replayability + config.minter_statefile = 'tmp/minter' + end # Prefix for Redis keys # config.redis_namespace = "hyrax" # Path to the file characterization tool - config.fits_path = "/home/appuser/fits-1.0.5/fits.sh" + config.fits_path = ENV['FITS_PATH'] || "/fits/fits-1.3.0/fits.sh" # Path to the file derivatives creation tool # config.libreoffice_path = "soffice" @@ -132,24 +145,23 @@ # * iiif_image_size_default # # Default is false - # config.iiif_image_server = false + config.iiif_image_server = true + if ENV.fetch('IIIF_TO_SERVE_SSL_URLS', 'false') == 'true' + protocol = 'https' + else + protocol = 'http' + end # Returns a URL that resolves to an image provided by a IIIF image server config.iiif_image_url_builder = lambda do |file_id, base_url, size| - Riiif::Engine.routes.url_helpers.image_url(file_id, host: base_url, size: size) + Riiif::Engine.routes.url_helpers.image_url(file_id, host: base_url, size: size, protocol: protocol) end - # config.iiif_image_url_builder = lambda do |file_id, base_url, size| - # "#{base_url}/downloads/#{file_id.split('/').first}" - # end # Returns a URL that resolves to an info.json file provided by a IIIF image server config.iiif_info_url_builder = lambda do |file_id, base_url| - uri = Riiif::Engine.routes.url_helpers.info_url(file_id, host: base_url) + uri = Riiif::Engine.routes.url_helpers.info_url(file_id, host: base_url, protocol: protocol) uri.sub(%r{/info\.json\Z}, '') end - # config.iiif_info_url_builder = lambda do |_, _| - # "" - # end # Returns a URL that indicates your IIIF image server compliance level # config.iiif_image_compliance_level_uri = 'http://iiif.io/api/image/2/level2.json' @@ -161,7 +173,7 @@ # config.iiif_metadata_fields = Hyrax::Forms::WorkForm.required_fields # Should a button with "Share my work" show on the front page to all users (even those not logged in)? - # config.display_share_button_when_not_logged_in = true + config.display_share_button_when_not_logged_in = false # The user who runs batch jobs. Update this if you aren't using emails # config.batch_user_key = 'batchuser@example.com' @@ -174,12 +186,12 @@ # Temporary paths to hold uploads before they are ingested into FCrepo # These must be lambdas that return a Pathname. Can be configured separately - # config.upload_path = ->() { Rails.root + 'tmp' + 'uploads' } - # config.cache_path = ->() { Rails.root + 'tmp' + 'uploads' + 'cache' } + config.upload_path = ->() { ENV.fetch('UPLOADS_PATH', Rails.root.join('tmp', 'uploads')) } + config.cache_path = ->() { ENV.fetch('CACHE_PATH', Rails.root.join('tmp', 'uploads', 'cache')) } # Location on local file system where derivatives will be stored # If you use a multi-server architecture, this MUST be a shared volume - # config.derivatives_path = Rails.root.join('tmp', 'derivatives') + config.derivatives_path = ENV.fetch('DERIVATIVES_PATH', Rails.root.join('tmp', 'derivatives')) # Should schema.org microdata be displayed? # config.display_microdata = true @@ -191,7 +203,7 @@ # Location on local file system where uploaded files will be staged # prior to being ingested into the repository or having derivatives generated. # If you use a multi-server architecture, this MUST be a shared volume. - # config.working_path = Rails.root.join( 'tmp', 'uploads') + config.working_path = ENV.fetch('UPLOADS_PATH', Rails.root.join('tmp', 'uploads')) # Should the media display partial render a download link? # config.display_media_download_link = true @@ -273,7 +285,10 @@ # config.whitelisted_ingest_dirs = [] end -Date::DATE_FORMATS[:standard] = "%m/%d/%Y" +DEFAULT_DATE_FORMAT = ENV['DEFAULT_DATE_FORMAT'] || '%d/%m/%Y' +Date::DATE_FORMATS[:standard] = DEFAULT_DATE_FORMAT +DateTime::DATE_FORMATS[:standard] = DEFAULT_DATE_FORMAT +Date::DATE_FORMATS[:default] = DEFAULT_DATE_FORMAT Qa::Authorities::Local.register_subauthority('subjects', 'Qa::Authorities::Local::TableBasedAuthority') Qa::Authorities::Local.register_subauthority('languages', 'Qa::Authorities::Local::TableBasedAuthority') diff --git a/hyrax/config/initializers/mailboxer.rb b/hyrax/config/initializers/mailboxer.rb index bc34b241..92b190ea 100644 --- a/hyrax/config/initializers/mailboxer.rb +++ b/hyrax/config/initializers/mailboxer.rb @@ -4,7 +4,7 @@ config.uses_emails = true #Configures the default from for emails sent for Messages and Notifications - config.default_from = "no-reply@mailboxer.com" + config.default_from = ENV['NOTIFICATIONS_EMAIL_DEFAULT_FROM_ADDRESS'] || "no-reply@mailboxer.com" #Configures the methods needed by mailboxer config.email_method = :mailboxer_email diff --git a/hyrax/config/initializers/oai_config.rb b/hyrax/config/initializers/oai_config.rb new file mode 100644 index 00000000..c17a7595 --- /dev/null +++ b/hyrax/config/initializers/oai_config.rb @@ -0,0 +1,13 @@ +OAI_CONFIG = + { + provider: { + repository_name: ENV['OAI_REPOSTIORY_NAME'], + repository_url: ENV['OAI_REPOSITORY_URL'], # todo: can we get this from the other places that use the base url? + record_prefix: ENV['OAI_RECORD_PREFIX'], + admin_email: ENV['OAI_ADMIN_EMAIL'], + sample_id: 'x059c7329' + }, + document: { + limit: 25, # number of records returned with each request, default: 15 + } + } \ No newline at end of file diff --git a/hyrax/config/initializers/qa.rb b/hyrax/config/initializers/qa.rb new file mode 100644 index 00000000..14692fef --- /dev/null +++ b/hyrax/config/initializers/qa.rb @@ -0,0 +1,7 @@ +Qa.config do |config| + # When enabled, CORS headers will be added to the responses for search and show. `OPTIONS` method will also be supported. + # Uncomment one of the lines below to enable or disable CORS headers. This configuration defaults to disabled when not set. + # More information on CORS headers at: https://fetch.spec.whatwg.org/#cors-protocol + # config.enable_cors_headers + # config.disable_cors_headers +end diff --git a/hyrax/config/initializers/session_store.rb b/hyrax/config/initializers/session_store.rb index 65463958..688ba657 100644 --- a/hyrax/config/initializers/session_store.rb +++ b/hyrax/config/initializers/session_store.rb @@ -1,3 +1,13 @@ # Be sure to restart your server when you modify this file. -Rails.application.config.session_store :cookie_store, key: '_hyrax_session' +# NB the cookie session store is not compatible with single sign out - so we shall use a Redis-based session store instead (redis-session-store gem) +redis_config = YAML.safe_load(ERB.new(IO.read(Rails.root.join('config', 'redis.yml'))).result)[Rails.env].with_indifferent_access +Rails.application.config.session_store :redis_session_store, { + key: '_hyrax_session', + redis: { + expire_after: 90.minutes, # cookie expiration + ttl: 90.minutes, # Redis expiration, defaults to 'expire_after' + key_prefix: 'hyrax:session:', + url: "redis://#{redis_config[:host]}:#{redis_config[:port]}/0", + } +} diff --git a/hyrax/config/initializers/sidekiq.rb b/hyrax/config/initializers/sidekiq.rb new file mode 100644 index 00000000..17c1aafd --- /dev/null +++ b/hyrax/config/initializers/sidekiq.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +config = YAML.safe_load(ERB.new(IO.read(Rails.root + 'config' + 'redis.yml')).result)[Rails.env].with_indifferent_access +redis_config = config.merge(thread_safe: true) + +Sidekiq::Logging.logger.level = Logger::WARN if ENV['RAILS_ENV'] == 'production' + +Sidekiq.configure_server do |s| + s.redis = redis_config +end + +Sidekiq.configure_client do |s| + s.redis = redis_config +end diff --git a/hyrax/config/initializers/thumbnail_path_service_override.rb b/hyrax/config/initializers/thumbnail_path_service_override.rb new file mode 100644 index 00000000..e8f9cb79 --- /dev/null +++ b/hyrax/config/initializers/thumbnail_path_service_override.rb @@ -0,0 +1,7 @@ +# Override Hyrax 2.6 to return default thumbnail for text +Hyrax::ThumbnailPathService.class_eval do + def call(object) + return default_image if object.file_set? && object.text? + super + end +end diff --git a/hyrax/config/initializers/willow_sword.rb b/hyrax/config/initializers/willow_sword.rb new file mode 100644 index 00000000..5699a37e --- /dev/null +++ b/hyrax/config/initializers/willow_sword.rb @@ -0,0 +1,27 @@ +WillowSword.setup do |config| + # The title used by the sword server, in the service document + config.title = 'MDR Sword V2 server' + # # If you do not want to use collections in Sword, it will use this as a default collection + # config.default_collection = {id: 'default', title: ['Default collection']} + # # The name of the model for retreiving collections (based on Hyrax integration) + # config.collection_models = ['Collection'] + # The work models supported by Sword (based on Hyrax integration) + config.work_models = ['Dataset'] + config.metadata_filename = 'api-fwk_depositUploadReq.xml' + # The fileset model supported by Sword (based on Hyrax integration) + # config.file_set_models = ['FileSet'] + # Remove all parameters that are not part of the model's permitted attributes + config.allow_only_permitted_attributes = false + # Default visibility for works + # config.default_visibility = 'open' + # XML crosswalk for creating a work + config.xw_from_xml_for_work = WillowSword::CrosswalkFromMdr + # XML crosswalk for creating a fileset + config.xw_from_xml_for_fileset = WillowSword::CrosswalkFromDc + # XML crosswalk when requesting a work + config.xw_to_xml_for_work = WillowSword::CrosswalkWorkToDc + # XML crosswalk when requesting a fileet + config.xw_to_xml_for_fileset = WillowSword::CrosswalkFilesetToDc + # Authorize Sword requests using Api-key header + config.authorize_request = false +end diff --git a/hyrax/config/initializers/work_form_override.rb b/hyrax/config/initializers/work_form_override.rb new file mode 100644 index 00000000..174cb570 --- /dev/null +++ b/hyrax/config/initializers/work_form_override.rb @@ -0,0 +1,10 @@ +# Overriding changes introduced to the initialize_field method in Hyrax commit +# https://github.com/samvera/hyrax/commit/89ffdb757a7ae545e303919d2277901237a5fd30 +# To solve issue https://github.com/CottageLabs/willow-hyrax/issues/6 +Rails.configuration.to_prepare do + Hyrax::Forms::WorkForm.class_eval do + def initialize_field(key) + super unless [:embargo_release_date, :lease_expiration_date].include?(key) + end + end +end diff --git a/hyrax/config/ldap.yml b/hyrax/config/ldap.yml new file mode 100644 index 00000000..1397d88d --- /dev/null +++ b/hyrax/config/ldap.yml @@ -0,0 +1,58 @@ +## Authorizations +# Uncomment out the merging for each environment that you'd like to include. +# You can also just copy and paste the tree (do not include the "authorizations") to each +# environment if you need something different per environment. +authorizations: &AUTHORIZATIONS + allow_unauthenticated_bind: false + group_base: ou=groups,dc=test,dc=com + ## Requires config.ldap_check_group_membership in devise.rb be true + # Can have multiple values, must match all to be authorized + required_groups: + # If only a group name is given, membership will be checked against "uniqueMember" + - cn=admins,ou=groups,dc=test,dc=com + - cn=users,ou=groups,dc=test,dc=com + # If an array is given, the first element will be the attribute to check against, the second the group name + - ["moreMembers", "cn=users,ou=groups,dc=test,dc=com"] + ## Requires config.ldap_check_attributes in devise.rb to be true + ## Can have multiple attributes and values, must match all to be authorized + require_attribute: + objectClass: inetOrgPerson + authorizationRole: postsAdmin + ## Requires config.ldap_check_attributes_presence in devise.rb to be true + ## Can have multiple attributes set to true or false to check presence, all must match all to be authorized + require_attribute_presence: + mail: true + telephoneNumber: true + serviceAccount: false + +## Environment + +development: + host: localhost + port: 389 + attribute: cn + base: ou=people,dc=test,dc=com + admin_user: cn=admin,dc=test,dc=com + admin_password: admin_password + ssl: false + # <<: *AUTHORIZATIONS + +test: + host: localhost + port: 3389 + attribute: cn + base: ou=people,dc=test,dc=com + admin_user: cn=admin,dc=test,dc=com + admin_password: admin_password + ssl: simple_tls + # <<: *AUTHORIZATIONS + +production: + host: <%= ENV['LDAP_HOST'] %> + port: <%= ENV['LDAP_PORT'] %> + attribute: <%= ENV['LDAP_ATTRIBUTE'] %> + base: <%= ENV['LDAP_BASE'] %> + admin_user: <%= ENV['LDAP_ADMIN_USER'] %> + admin_password: <%= ENV['LDAP_ADMIN_PASSWORD'] %> + ssl: <%= ENV['LDAP_SSL'] %> + # <<: *AUTHORIZATIONS diff --git a/hyrax/config/locales/dataset.de.yml b/hyrax/config/locales/dataset.de.yml new file mode 100644 index 00000000..c133f7be --- /dev/null +++ b/hyrax/config/locales/dataset.de.yml @@ -0,0 +1,8 @@ +de: + hyrax: + icons: + dataset: 'fa fa-file-text-o' + select_type: + dataset: + description: "Dataset Werke" + name: "Dataset" diff --git a/hyrax/config/locales/dataset.en.yml b/hyrax/config/locales/dataset.en.yml new file mode 100644 index 00000000..40244206 --- /dev/null +++ b/hyrax/config/locales/dataset.en.yml @@ -0,0 +1,39 @@ +en: + hyrax: + icons: + dataset: 'fa fa-file-text-o' + select_type: + dataset: + description: "Dataset works" + name: "Dataset" + browse_dataset: "Browse all datasets" + browse_publication: "Browse all publications" + browse_collection: "Browse all collections" + simple_form: + labels: + dataset: + analysis_field: "Analysis field" + characterization_methods: "Characterization methods" + complex_date: "Date" + complex_identifier: "Identifier" + complex_organization: "Organization" + complex_person: "Creator" + complex_relation: "Related item" + complex_rights: "Rights" + complex_version: "Version" + computational_methods: "Computational methods" + custom_property: "Additional metadata" + data_origin: "Data origin" + complex_instrument: "Instrument" + material_types: "Material types " + measurement_environment: "Measurement environment" + origin_system_provenance: "Origin system provenance" + part_of: "Part of" + processing_environment: "Processing environment" + properties_addressed: "Properties addressed" + specimen_set: "Specimen" + complex_specimen_type: "Specimen type" + complex_structural_features: "Structural features" + synthesis_and_processing: "Synthesis and processing" + status_at_start: "Status at start" + status_at_end: "Status at end" diff --git a/hyrax/config/locales/dataset.es.yml b/hyrax/config/locales/dataset.es.yml new file mode 100644 index 00000000..cd4e7fbd --- /dev/null +++ b/hyrax/config/locales/dataset.es.yml @@ -0,0 +1,10 @@ +es: + hyrax: + icons: + dataset: 'fa fa-file-text-o' + select_type: + dataset: + # TODO: translate `human_name` into Spanish + description: "Dataset trabajos" + name: "Dataset" + # TODO: translate `human_name` into Spanish diff --git a/hyrax/config/locales/dataset.fr.yml b/hyrax/config/locales/dataset.fr.yml new file mode 100644 index 00000000..f59979a3 --- /dev/null +++ b/hyrax/config/locales/dataset.fr.yml @@ -0,0 +1,8 @@ +fr: + hyrax: + icons: + dataset: 'fa fa-file-text-o' + select_type: + dataset: + description: "Dataset œuvres" + name: "Dataset" diff --git a/hyrax/config/locales/dataset.it.yml b/hyrax/config/locales/dataset.it.yml new file mode 100644 index 00000000..bd37f833 --- /dev/null +++ b/hyrax/config/locales/dataset.it.yml @@ -0,0 +1,8 @@ +it: + hyrax: + icons: + dataset: 'fa fa-file-text-o' + select_type: + dataset: + description: "Dataset opere" + name: "Dataset" diff --git a/hyrax/config/locales/dataset.pt-BR.yml b/hyrax/config/locales/dataset.pt-BR.yml new file mode 100644 index 00000000..3b9ed8c1 --- /dev/null +++ b/hyrax/config/locales/dataset.pt-BR.yml @@ -0,0 +1,8 @@ +pt-BR: + hyrax: + icons: + dataset: 'fa fa-file-text-o' + select_type: + dataset: + description: "Dataset trabalhos" + name: "Dataset" diff --git a/hyrax/config/locales/dataset.zh.yml b/hyrax/config/locales/dataset.zh.yml new file mode 100644 index 00000000..f9d1a533 --- /dev/null +++ b/hyrax/config/locales/dataset.zh.yml @@ -0,0 +1,10 @@ +zh: + hyrax: + icons: + dataset: 'fa fa-file-text-o' + select_type: + dataset: + # TODO: translate `human_name` into Chinese + description: "Dataset 作品" + name: "Dataset" + # TODO: translate `human_name` into Chinese diff --git a/hyrax/config/locales/en.yml b/hyrax/config/locales/en.yml index 06539571..44179a6a 100644 --- a/hyrax/config/locales/en.yml +++ b/hyrax/config/locales/en.yml @@ -1,23 +1,56 @@ -# Files in the config/locales directory are used for internationalization -# and are automatically loaded by Rails. If you want to use locales other -# than English, add the necessary files in this directory. -# -# To use the locales, use `I18n.t`: -# -# I18n.t 'hello' -# -# In views, this is aliased to just `t`: -# -# <%= t('hello') %> -# -# To use a different locale, set it with `I18n.locale`: -# -# I18n.locale = :es -# -# This would use the information in config/locales/es.yml. -# -# To learn more, please read the Rails Internationalization guide -# available at http://guides.rubyonrails.org/i18n.html. - en: - hello: "Hello world" + ngdr: + fields: + alternative_title: "Alternative title" + analysis_field: "Analysis field" + category: "Category" + characterization_methods: "Characterization methods" + computational_methods: "Computational methods" + custom_property: "Additional metadata" + column_number: "Column number" + complex_affiliation: "Affiliation" + complex_chemical_composition: "Chemical composition" + complex_crystallographic_structure: "Crystallographic structure" + complex_date: "Date" + complex_event: "Event" + complex_identifier: "Identifier" + complex_instrument: "Instrument" + complex_material_type: "Material type" + complex_organization: "Organization" + complex_person: "Creator" + complex_purchase_record: "Purchase record" + complex_relation: "Related item" + complex_rights: "Rights" + complex_shape: "Shape" + complex_source: "Journal" + complex_specimen_type: "Specimen type" + complex_state_of_matter: "State of matter" + complex_structural_feature: "Structural feature" + complex_version: "Version" + data_origin: "Data origin" + first_name: "First name" + instrument: "Instrument" + issue: "Issue" + instrument_function: "Instrument function" + last_name: "Last name" + managing_organization: "Managing organization" + material_sub_type: "Material sub type" + material_type: "Material type" + model_number: "Model number" + measurement_environment: "Measurement environment" + origin_system_provenance: "Origin system provenance" + part_of: "Part of" + place: "Location" + processing_environment: "Processing environment" + properties_addressed: "Properties addressed" + purchase_record_item: "Purchase record item" + specimen_set: "Specimen" + specimen_type: "Specimen type" + status: "Status" + status_at_end: "Status at end" + status_at_start: "Status at start" + structural_features: "Structural features" + sub_category: "Sub category" + sub_organization: "Sub organization" + synthesis_and_processing: "Synthesis and processing" + total_number_of_pages: "Number of pages" diff --git a/hyrax/config/locales/hyrax.en.yml b/hyrax/config/locales/hyrax.en.yml index 3f096bcb..beea6fec 100644 --- a/hyrax/config/locales/hyrax.en.yml +++ b/hyrax/config/locales/hyrax.en.yml @@ -6,53 +6,256 @@ en: facet: based_near_label_sim: Location creator_sim: Creator + characterization_methods_sim: Characterization methods + complex_date_dtsim: Date + complex_date_accepted_dtsim: Date accepted + complex_year_accepted_sim: Date accepted + complex_date_available_dtsim: Date available + complex_year_available_sim: Date available + complex_date_copyrighted_dtsim: Date copyrighted + complex_year_copyrighted_sim: Date copyrighted + complex_date_collected_dtsim: Date collected + complex_year_collected_sim: Date collected + complex_date_created_dtsim: Date created + complex_year_created_sim: Date created + complex_date_issued_dtsim: Date issued + complex_year_issued_sim: Date issued + complex_date_published_dtsim: Date published + complex_year_published_sim: Date published + complex_date_submitted_dtsim: Date submitted + complex_year_submitted_sim: Date submitted + complex_date_updated_dtsim: Date updated + complex_year_updated_sim: Date updated + complex_date_valid_dtsim: Date valid + complex_year_valid_sim: Date valid + complex_date_processed_dtsim: Date processed + complex_year_processed_sim: Date processed + complex_date_purchased_dtsim: Date purchased + complex_year_purchased_sim: Date purchased + complex_date_other_dtsim: Date + complex_year_other_sim: Date + complex_event_sim: Event + complex_material_sub_type_sim: Material sub type + complex_material_type_sim: Material type + complex_organization_sim: Organization + complex_person_other_sim: Creator + complex_person_author_sim: Author + complex_person_editor_sim: Editor + complex_person_translator_sim: Translator + complex_person_data_depositor_sim: Data depositor + complex_person_data_curator_sim: Data curator + complex_person_operator_sim: Operator + complex_person_organization_sim: Organization + complex_person_sub_organization_sim: Sub organization + complex_purchase_record_manufacturer_sim: Purchase record manufacturer + complex_purchase_record_manufacturer_sub_organization_sim: Purchase record manufacturer sub organization + complex_purchase_record_supplier_sim: Purchase record supplier + complex_purchase_record_supplier_sub_organization_sim: Purchase record supplier sub organization + complex_relation_relationship_sim: Relationship + complex_rights_sim: License + complex_structural_feature_category_sim: Structural feature category + complex_structural_feature_sub_category_sim: Structural feature sub category + complex_source_title_sim: Journal + complex_sub_organization_sim: Sub organization + complex_person_sim: Creator + computational_methods_sim: Computational methods + custom_property_sim: Additional metadata + data_origin_sim: Data origin file_format_sim: Format generic_type_sim: Type + human_readable_type_sim: Type of work + instrument_sim: Instrument + instrument_managing_organization_sim: Instrument managing organization + instrument_managing_sub_organization_sim: Instrument managing sub organization + instrument_manufacturer_sim: Instrument manufacturer + instrument_manufacturer_sub_organization_sim: Instrument manufacturer sub organization + instrument_model_number_sim: Instrument model number + instrument_organization_sim: Instrument organization keyword_sim: Keyword language_sim: Language + place_sim: Location + properties_addressed_sim: Properties addressed publisher_sim: Publisher + specimen_set_sim: Specimen subject_sim: Subject + synthesis_and_processing_sim: Synthesis and processing index: based_near_tesim: Location + characterization_methods_tesim: Characterization methods contributor_tesim: Contributor creator_tesim: Creator + complex_chemical_composition_tesim: Chemical composition + complex_chemical_composition_identifier_ssim: Chemical composition identifier + complex_crystallographic_structure_tesim: Crystallographic structure + complex_crystallographic_structure_identifier_ssim: Crystallographic structure identifier + complex_date_dtsim: Date + complex_date_accepted_dtsim: Date accepted + complex_date_available_dtsim: Date available + complex_date_copyrighted_dtsim: Date copyrighted + complex_date_collected_dtsim: Date collected + complex_date_created_dtsim: Date created + complex_date_issued_dtsim: Date issued + complex_date_published_dtsim: Date published + complex_date_submitted_dtsim: Date submitted + complex_date_updated_dtsim: Date updated + complex_date_valid_dtsim: Date valid + complex_date_processed_dtsim: Date processed + complex_date_purchased_dtsim: Date purchased + complex_date_other_dtsim: Date + complex_material_sub_type_tesim: Material sub type + complex_material_type_tesim: Material type + complex_material_type_description_tesim: Material type description + complex_material_type_identifier_ssim: Material identifier + complex_identifier_ssim: Identifier + complex_identifier_orcid_ssim: Orcid + complex_identifier_local_id_ssim: Local identifier + complex_person_other_tesim: Creator + # use Creator for label in search results - see i131 (was Author) + complex_person_author_tesim: Creator + complex_person_editor_tesim: Editor + complex_person_translator_tesim: Translator + # use Creator for label - see i131 (was Data depositor) + complex_person_data_depositor_tesim: Creator + complex_person_data_curator_tesim: Data curator + complex_person_operator_tesim: Operator + complex_person_organization_tesim: Organization + complex_person_sub_organization_tesim: Sub organization + complex_purchase_record_item_tesim: Purchase record item + complex_purchase_record_title_tesim: Purchase record title + complex_purchase_record_identifier_ssim: Purchase record identifier + complex_purchase_record_manufacturer_tesim: Purchase record manufacturer + complex_purchase_record_manufacturer_sub_organization_tesim: Purchase record manufacturer sub organization + complex_purchase_record_supplier_tesim: Purchase record supplier + complex_purchase_record_supplier_sub_organization_tesim: Purchase record supplier sub organization + complex_relation_title_tesim: Title of related item + complex_shape_tesim: Shape + complex_shape_identifier_ssim: Shape identifier + complex_source_title_tesim: Journal + complex_specimen_type_tesim: Specimen type + complex_specimen_type_description_tesim: Specimen description + complex_specimen_type_identifier_ssim: Specimen identifier + complex_state_of_matter_tesim: State of matter + complex_state_of_matter_identifier_ssim: State of matter identifier + complex_structural_feature_category_tesim: Structural feature category + complex_structural_feature_description_tesim: Structural feature description + complex_structural_feature_sub_category_tesim: Structural feature sub category + complex_structural_feature_identifier_ssim: Structural feature identifier + complex_version_ssim: Version + computational_methods_tesim: Computational methods + custom_property_tesim: Additional metadata + data_origin_tesim: Data origin date_created_tesim: Date Created date_modified_dtsi: Date Modified date_uploaded_dtsi: Date Uploaded description_tesim: Description file_format_tesim: File Format identifier_tesim: Identifier + instrument_alternative_title_tesim: Instrument alternative title + instrument_description_tesim: Instrument description + instrument_identifier_ssim: Instrument identifier + instrument_managing_organization_tesim: Instrument managing organization + instrument_managing_sub_organization_tesim: Instrument managing sub organization + instrument_manufacturer_tesim: Instrument manufacturer + instrument_manufacturer_sub_organization_tesim: Instrument manufacturer sub organization + instrument_model_number_tesim: Instrument model number + instrument_title_tesim: Instrument title keyword_tesim: Keyword language_tesim: Language license_tesim: License + origin_system_provenance_tesim: Origin system provenance + properties_addressed_tesim: Properties addressed publisher_tesim: Publisher rights_statement_tesim: Rights Statement + specimen_set_tesim: Specimen subject_tesim: Subject + synthesis_and_processing_tesim: Synthesis and processing show: + alternative_title_tesim: Alternative title based_near_tesim: Location + characterization_methods_tesim: Characterization_methods + computational_methods_tesim: Computational methods contributor_tesim: Contributor + complex_date_ssm: "Date" + complex_date_accepted_ssm: Date accepted + complex_date_available_ssm: Date available + complex_date_copyrighted_ssm: Date copyrighted + complex_date_collected_ssm: Date collected + complex_date_created_ssm: Date created + complex_date_issued_ssm: Date issued + complex_date_published_ssm: Date published + complex_date_submitted_ssm: Date submitted + complex_date_updated_ssm: Date updated + complex_date_valid_ssm: Date valid + complex_date_processed_ssm: Date processed + complex_date_purchased_ssm: Date purchased + complex_date_other_ssm: Date + complex_event_ssm: Event + complex_identifier_ssm: Identifier + complex_instrument_ssm: Instrument + complex_organization_ssm: Organization + complex_person_ssm: Creator + complex_person_other_ssm: Creator + complex_person_author_ssm: Author + complex_person_editor_ssm: Editor + complex_person_translator_ssm: Translator + complex_person_data_depositor_ssm: Data depositor + complex_person_data_curator_ssm: Data curator + complex_person_operator_ssm: Operator + complex_person_organization_ssm: Organization + complex_person_sub_organization_ssm: Sub organization + complex_relation_ssm: Related item + complex_rights_ssm: License + complex_source_ssm: Journal + complex_specimen_type_ssm: Specimen type + complex_version_ssm: Version creator_tesim: Creator + custom_property_ssm: Additional metadata + data_origin_tesim: Data origin date_created_tesim: Date Created date_modified_dtsi: Date Modified date_uploaded_dtsi: Date Uploaded description_tesim: Description file_format_tesim: File Format identifier_tesim: Identifier + instrument_tesim: Instrument + issue_tesim: Issue keyword_tesim: Keyword language_tesim: Language license_tesim: License + origin_system_provenance_tesim: Origin system provenance + place_tesim: Location + properties_addressed_tesim: Properties processed publisher_tesim: Publisher rights_statement_tesim: Rights Statement + specimen_type_tesim: Specimen subject_tesim: Subject + synthesis_and_processing_tesim: Synthesis and processing + table_of_contents_tesim: Table of contents title_tesim: Title hyrax: account_name: My Institution Account Id directory: suffix: "@example.org" footer: - copyright_html: "Copyright © 2017 Samvera Licensed under the Apache License, Version 2.0" + copyright_html: "Copyright © National Institute for Materials Science" service_html: A service of Samvera. + address_html: National Institute for Materials Science (NIMS) 1-2-1 Sengen, Tsukuba, Ibaraki 305-0047 JAPAN institution_name: Institution institution_name_full: The Institution Name - product_name: Hyrax + product_name: MDR product_twitter_handle: "@SamveraRepo" + works: + form: + tab: + files: Files + metadata: Descriptions + method: Method + instrument: Instruments + relationships: Relationships + share: Sharing + specimen: Specimen details + visibility: + embargo: + note_html: This option is not valid. + lease: + note_html: This option is not valid. diff --git a/hyrax/config/locales/image.de.yml b/hyrax/config/locales/image.de.yml new file mode 100644 index 00000000..1a7e6644 --- /dev/null +++ b/hyrax/config/locales/image.de.yml @@ -0,0 +1,8 @@ +de: + hyrax: + icons: + image: 'fa fa-file-text-o' + select_type: + image: + description: "Image Werke" + name: "Image" diff --git a/hyrax/config/locales/image.en.yml b/hyrax/config/locales/image.en.yml new file mode 100644 index 00000000..715e817f --- /dev/null +++ b/hyrax/config/locales/image.en.yml @@ -0,0 +1,18 @@ +en: + hyrax: + icons: + image: 'fa fa-file-text-o' + select_type: + image: + description: "Image works" + name: "Image" + simple_form: + labels: + image: + complex_person: "Creator" + complex_identifier: "Identifier" + part_of: "Part of" + complex_date: "Date" + complex_rights: "Rights" + complex_version: "Version" + status: "Status" diff --git a/hyrax/config/locales/image.es.yml b/hyrax/config/locales/image.es.yml new file mode 100644 index 00000000..5ec9c065 --- /dev/null +++ b/hyrax/config/locales/image.es.yml @@ -0,0 +1,10 @@ +es: + hyrax: + icons: + image: 'fa fa-file-text-o' + select_type: + image: + # TODO: translate `human_name` into Spanish + description: "Image trabajos" + name: "Image" + # TODO: translate `human_name` into Spanish diff --git a/hyrax/config/locales/image.fr.yml b/hyrax/config/locales/image.fr.yml new file mode 100644 index 00000000..48b5a226 --- /dev/null +++ b/hyrax/config/locales/image.fr.yml @@ -0,0 +1,8 @@ +fr: + hyrax: + icons: + image: 'fa fa-file-text-o' + select_type: + image: + description: "Image œuvres" + name: "Image" diff --git a/hyrax/config/locales/image.it.yml b/hyrax/config/locales/image.it.yml new file mode 100644 index 00000000..4fa892e8 --- /dev/null +++ b/hyrax/config/locales/image.it.yml @@ -0,0 +1,8 @@ +it: + hyrax: + icons: + image: 'fa fa-file-text-o' + select_type: + image: + description: "Image opere" + name: "Image" diff --git a/hyrax/config/locales/image.pt-BR.yml b/hyrax/config/locales/image.pt-BR.yml new file mode 100644 index 00000000..eef53068 --- /dev/null +++ b/hyrax/config/locales/image.pt-BR.yml @@ -0,0 +1,8 @@ +pt-BR: + hyrax: + icons: + image: 'fa fa-file-text-o' + select_type: + image: + description: "Image trabalhos" + name: "Image" diff --git a/hyrax/config/locales/image.zh.yml b/hyrax/config/locales/image.zh.yml new file mode 100644 index 00000000..aa7a88b8 --- /dev/null +++ b/hyrax/config/locales/image.zh.yml @@ -0,0 +1,10 @@ +zh: + hyrax: + icons: + image: 'fa fa-file-text-o' + select_type: + image: + # TODO: translate `human_name` into Chinese + description: "Image 作品" + name: "Image" + # TODO: translate `human_name` into Chinese diff --git a/hyrax/config/locales/publication.de.yml b/hyrax/config/locales/publication.de.yml new file mode 100644 index 00000000..4688db18 --- /dev/null +++ b/hyrax/config/locales/publication.de.yml @@ -0,0 +1,8 @@ +de: + hyrax: + icons: + publication: 'fa fa-file-text-o' + select_type: + publication: + description: "Publication Werke" + name: "Publication" diff --git a/hyrax/config/locales/publication.en.yml b/hyrax/config/locales/publication.en.yml new file mode 100644 index 00000000..70845a5c --- /dev/null +++ b/hyrax/config/locales/publication.en.yml @@ -0,0 +1,24 @@ +en: + hyrax: + icons: + publication: 'fa fa-file-text-o' + select_type: + publication: + description: "Publication works" + name: "Publication" + simple_form: + labels: + publication: + complex_date: "Date" + complex_event: "Event" + complex_identifier: "Identifier" + complex_organization: "Organization" + complex_person: "Creator" + complex_relation: "Related item" + complex_rights: "Rights" + complex_source: "Journal/Book/Proceedings/Database" + complex_version: "Version" + part_of: "Part of" + issue: "Issue" + place: "Location" + total_number_of_pages: "Number of pages" diff --git a/hyrax/config/locales/publication.es.yml b/hyrax/config/locales/publication.es.yml new file mode 100644 index 00000000..7d2fb6b9 --- /dev/null +++ b/hyrax/config/locales/publication.es.yml @@ -0,0 +1,10 @@ +es: + hyrax: + icons: + publication: 'fa fa-file-text-o' + select_type: + publication: + # TODO: translate `human_name` into Spanish + description: "Publication trabajos" + name: "Publication" + # TODO: translate `human_name` into Spanish diff --git a/hyrax/config/locales/publication.fr.yml b/hyrax/config/locales/publication.fr.yml new file mode 100644 index 00000000..753e4a91 --- /dev/null +++ b/hyrax/config/locales/publication.fr.yml @@ -0,0 +1,8 @@ +fr: + hyrax: + icons: + publication: 'fa fa-file-text-o' + select_type: + publication: + description: "Publication œuvres" + name: "Publication" diff --git a/hyrax/config/locales/publication.it.yml b/hyrax/config/locales/publication.it.yml new file mode 100644 index 00000000..8a280b58 --- /dev/null +++ b/hyrax/config/locales/publication.it.yml @@ -0,0 +1,8 @@ +it: + hyrax: + icons: + publication: 'fa fa-file-text-o' + select_type: + publication: + description: "Publication opere" + name: "Publication" diff --git a/hyrax/config/locales/publication.pt-BR.yml b/hyrax/config/locales/publication.pt-BR.yml new file mode 100644 index 00000000..13babea3 --- /dev/null +++ b/hyrax/config/locales/publication.pt-BR.yml @@ -0,0 +1,8 @@ +pt-BR: + hyrax: + icons: + publication: 'fa fa-file-text-o' + select_type: + publication: + description: "Publication trabalhos" + name: "Publication" diff --git a/hyrax/config/locales/publication.zh.yml b/hyrax/config/locales/publication.zh.yml new file mode 100644 index 00000000..b88a2367 --- /dev/null +++ b/hyrax/config/locales/publication.zh.yml @@ -0,0 +1,10 @@ +zh: + hyrax: + icons: + publication: 'fa fa-file-text-o' + select_type: + publication: + # TODO: translate `human_name` into Chinese + description: "Publication 作品" + name: "Publication" + # TODO: translate `human_name` into Chinese diff --git a/hyrax/config/oclcts-authorities.yml b/hyrax/config/oclcts-authorities.yml new file mode 100644 index 00000000..925fcf07 --- /dev/null +++ b/hyrax/config/oclcts-authorities.yml @@ -0,0 +1,24 @@ +url-pattern: + prefix-query: http://tspilot.oclc.org/{authority-id}/?query=oclcts.rootHeading+exact+%22{query}*%22&version=1.1&operation=searchRetrieve&recordSchema=http%3A%2F%2Fzthes.z3950.org%2Fxml%2F1.0%2F&maximumRecords=10&startRecord=1&resultSetTTL=300&recordPacking=xml&recordXPath=&sortKeys= + id-lookup: http://tspilot.oclc.org/{authority-id}/?query=dc.identifier+exact+%22{id}%22&version=1.1&operation=searchRetrieve&recordSchema=http%3A%2F%2Fzthes.z3950.org%2Fxml%2F1.0%2F&maximumRecords=10&startRecord=1&resultSetTTL=300&recordPacking=xml&recordXPath=&sortKeys= +authorities: + lcgft: + name: Library of Congress Genre/Form Terms for Library and Archival Materials (LCGFT) + bisacsh: + name: Book Industry Study Group Subject Headings (BISAC®). Used with permission. + fast: + name: Faceted Application of Subject Terminology (FAST subject headings) + gsafd: + name: Form and genre headings for fiction and drama + lcshac: + name: Library of Congress AC Subject Headings + lcsh: + name: Library of Congress Subject Headings + mesh: + name: Medical Subject Headings (MeSH®) + lctgm: + name: "Thesaurus for graphic materials: TGM I, Subject terms" + gmgpc: + name: "Thesaurus for graphic materials: TGM II, Genre terms" + meta: + name: Controlled Vocabulary Metadata diff --git a/hyrax/config/puma.rb b/hyrax/config/puma.rb index 716534d4..ebb4bcb8 100644 --- a/hyrax/config/puma.rb +++ b/hyrax/config/puma.rb @@ -1,13 +1,13 @@ # Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers a minimum and maximum. +# The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum, this matches the default thread size of Active Record. +# and maximum; this matches the default thread size of Active Record. # threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i threads threads_count, threads_count -# Specifies the `port` that Puma will listen on to receive requests, default is 3000. +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. # port ENV.fetch("PORT") { 3000 } @@ -32,16 +32,25 @@ # # preload_app! +# If you are preloading your application and using Active Record, it's +# recommended that you close any connections to the database before workers +# are forked to prevent connection leakage. +# +# before_fork do +# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) +# end + # The code in the `on_worker_boot` will be called if you are using # clustered mode by specifying a number of `workers`. After each worker -# process is booted this block will be run, if you are using `preload_app!` -# option you will want to use this block to reconnect to any threads -# or connections that may have been created at application boot, Ruby +# process is booted, this block will be run. If you are using the `preload_app!` +# option, you will want to use this block to reconnect to any threads +# or connections that may have been created at application boot, as Ruby # cannot share connections between processes. # # on_worker_boot do # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) # end +# # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart @@ -53,7 +62,7 @@ bind "unix://#{shared_dir}/sockets/puma.sock" # Logging -stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true +# stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true # Set master PID and state locations pidfile "#{shared_dir}/pids/puma.pid" diff --git a/hyrax/config/redis.yml b/hyrax/config/redis.yml index 3888eaf4..2280ebb7 100644 --- a/hyrax/config/redis.yml +++ b/hyrax/config/redis.yml @@ -1,9 +1,9 @@ development: - host: localhost - port: 6379 + host: <%= ENV.fetch('REDIS_HOST', 'localhost') %> + port: <%= ENV.fetch('REDIS_PORT', '6379') %> test: - host: localhost - port: 6379 + host: <%= ENV.fetch('REDIS_HOST', 'localhost') %> + port: <%= ENV.fetch('REDIS_PORT', '6379') %> production: - host: localhost - port: 6379 + host: <%= ENV.fetch('REDIS_HOST', 'redis') %> + port: <%= ENV.fetch('REDIS_PORT', '6379') %> diff --git a/hyrax/config/routes.rb b/hyrax/config/routes.rb index e729c243..2d78725b 100644 --- a/hyrax/config/routes.rb +++ b/hyrax/config/routes.rb @@ -1,34 +1,50 @@ Rails.application.routes.draw do + mount WillowSword::Engine => '/sword' mount Riiif::Engine => 'images', as: :riiif if Hyrax.config.iiif_image_server? - mount Blacklight::Engine => '/' - - concern :searchable, Blacklight::Routes::Searchable.new + # This needs to appear before Hyrax's routes else sign_in and sign_out break + devise_for :users, controllers: {sessions: 'users/sessions'} - resource :catalog, only: [:index], as: 'catalog', path: '/catalog', controller: 'catalog' do - concerns :searchable + authenticate :user, lambda { |u| u.admin? } do + require 'sidekiq/web' + mount Sidekiq::Web => '/sidekiq' end - devise_for :users - mount Hydra::RoleManagement::Engine => '/' - + mount BrowseEverything::Engine => '/browse' mount Qa::Engine => '/authorities' + mount Blacklight::Engine => '/' + mount Hydra::RoleManagement::Engine => '/' mount Hyrax::Engine, at: '/' - resources :welcome, only: 'index' - root 'hyrax/homepage#index' - curation_concerns_basic_routes + concern :exportable, Blacklight::Routes::Exportable.new + concern :searchable, Blacklight::Routes::Searchable.new + #concern :oai_provider, BlacklightOaiProvider::Routes::Provider.new # Temporarily disable API behaviour, see https://github.com/antleaf/nims-mdr-development/issues/241 - resources :solr_documents, only: [:show], path: '/catalog', controller: 'catalog' do - concerns :exportable - end + curation_concerns_basic_routes resources :bookmarks do concerns :exportable - collection do delete 'clear' end end + resource :catalog, only: [:index], as: 'catalog', path: '/catalog', controller: 'catalog' do + #concerns :oai_provider # Temporarily disable API behaviour, see https://github.com/antleaf/nims-mdr-development/issues/241 + concerns :searchable + end + + resources :solr_documents, only: [:show], path: '/catalog', controller: 'catalog' do + concerns :exportable + end + + resources :files, only: [] do + member do + get :export, controller: :exports + end + end + + resources :welcome, only: 'index' + root 'hyrax/homepage#index' + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end diff --git a/hyrax/config/sidekiq.yml b/hyrax/config/sidekiq.yml new file mode 100644 index 00000000..ef341fe3 --- /dev/null +++ b/hyrax/config/sidekiq.yml @@ -0,0 +1,4 @@ +--- +:queues: + - default + - ingest \ No newline at end of file diff --git a/hyrax/config/solr.yml b/hyrax/config/solr.yml index 4cb35238..f0b152cb 100644 --- a/hyrax/config/solr.yml +++ b/hyrax/config/solr.yml @@ -1,7 +1,8 @@ -# This is a sample config file that points to a solr server for each environment +# NB: the URLs in this file should match those in blacklight.yml + development: - url: http://127.0.0.1:<%= ENV['SOLR_TEST_PORT'] || 8983 %>/solr/hydra-development + url: <%= ENV['SOLR_URL_SCHEME'] || 'http' %>://<%= ENV['SOLR_HOST'] || '127.0.0.1' %>:<%= ENV['SOLR_PORT'] || '8983' %>/solr/hydra-development test: - url: http://127.0.0.1:<%= ENV['SOLR_TEST_PORT'] || 8985 %>/solr/hydra-test + url: <%= ENV['SOLR_URL_SCHEME'] || 'http' %>://<%= ENV['SOLR_HOST'] || '127.0.0.1' %>:<%= ENV['SOLR_TEST_PORT'] || '8985' %>/solr/hydra-test production: - url: http://your.production.server:8080/bl_solr/core0 + url: <%= ENV['SOLR_URL_SCHEME'] || 'http' %>://<%= ENV['SOLR_HOST'] || 'solr' %>:<%= ENV['SOLR_PORT'] || '8983' %>/solr/hyrax_production diff --git a/hyrax/config/solr_wrapper_test.yml b/hyrax/config/solr_wrapper_test.yml index 337de21b..873217e6 100644 --- a/hyrax/config/solr_wrapper_test.yml +++ b/hyrax/config/solr_wrapper_test.yml @@ -1,8 +1,11 @@ #config/solr_wrapper_test.yml -# version: 6.1.0 +verbose: false +cloud: false port: 8985 -instance_dir: tmp/solr-test +version: '7.7.2' # NB: ideally this should match the version in docker-compose.yml +download_dir: 'tmp' +instance_dir: 'tmp/solr-test' collection: + name: 'hydra-test' + dir: 'solr/config' persist: false - dir: solr/config - name: hydra-test diff --git a/hyrax/config/tinymce.yml b/hyrax/config/tinymce.yml index 689d00f0..94f78db8 100644 --- a/hyrax/config/tinymce.yml +++ b/hyrax/config/tinymce.yml @@ -1,12 +1,12 @@ default: &default setup: tinymce_nav_safety # onChange event init -content_block: - <<: *default menubar: false toolbar1: styleselect | bold italic | link image | undo redo toolbar2: table | fullscreen | uploadimage plugins: - table - fullscreen +content_block: + <<: *default custom: <<: *default diff --git a/hyrax/config/uv/uv-config.json b/hyrax/config/uv/uv-config.json new file mode 100644 index 00000000..077404aa --- /dev/null +++ b/hyrax/config/uv/uv-config.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/hyrax/config/uv/uv.html b/hyrax/config/uv/uv.html new file mode 100644 index 00000000..3334836e --- /dev/null +++ b/hyrax/config/uv/uv.html @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/hyrax/config/workflows/mediated_deposit_workflow.json b/hyrax/config/workflows/mediated_deposit_workflow.json index 4ab7fad3..fd4fe40e 100644 --- a/hyrax/config/workflows/mediated_deposit_workflow.json +++ b/hyrax/config/workflows/mediated_deposit_workflow.json @@ -18,6 +18,7 @@ } ], "methods": [ + "Hyrax::Workflow::GrantReadToDepositor", "Hyrax::Workflow::DeactivateObject" ] }, { diff --git a/hyrax/db/migrate/20180430195039_devise_create_users.rb b/hyrax/db/migrate/20180430195039_devise_create_users.rb index 67a5b786..50b1cfcc 100644 --- a/hyrax/db/migrate/20180430195039_devise_create_users.rb +++ b/hyrax/db/migrate/20180430195039_devise_create_users.rb @@ -36,7 +36,7 @@ def change t.timestamps null: false end - add_index :users, :email, unique: true + add_index :users, :email add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true diff --git a/hyrax/db/migrate/20190122162320_add_username_to_users.rb b/hyrax/db/migrate/20190122162320_add_username_to_users.rb new file mode 100644 index 00000000..c9b3c3ff --- /dev/null +++ b/hyrax/db/migrate/20190122162320_add_username_to_users.rb @@ -0,0 +1,6 @@ +class AddUsernameToUsers < ActiveRecord::Migration[5.1] + def change + add_column :users, :username, :string + add_index :users, :username, unique: true + end +end diff --git a/hyrax/db/migrate/20190822033353_add_lockable_to_user.rb b/hyrax/db/migrate/20190822033353_add_lockable_to_user.rb new file mode 100644 index 00000000..47a182b3 --- /dev/null +++ b/hyrax/db/migrate/20190822033353_add_lockable_to_user.rb @@ -0,0 +1,7 @@ +class AddLockableToUser < ActiveRecord::Migration[5.1] + def change + add_column :users, :failed_attempts, :integer, default: 0, null: false + add_column :users, :unlock_token, :string + add_column :users, :locked_at, :datetime + end +end diff --git a/hyrax/db/migrate/20190930025332_add_remember_token_to_user.rb b/hyrax/db/migrate/20190930025332_add_remember_token_to_user.rb new file mode 100644 index 00000000..80a85c18 --- /dev/null +++ b/hyrax/db/migrate/20190930025332_add_remember_token_to_user.rb @@ -0,0 +1,5 @@ +class AddRememberTokenToUser < ActiveRecord::Migration[5.1] + def change + add_column :users, :remember_token, :string + end +end diff --git a/hyrax/db/migrate/20191111115624_index_qa_local_authority_entries_on_lower_label.rb b/hyrax/db/migrate/20191111115624_index_qa_local_authority_entries_on_lower_label.rb new file mode 100644 index 00000000..6f1363c0 --- /dev/null +++ b/hyrax/db/migrate/20191111115624_index_qa_local_authority_entries_on_lower_label.rb @@ -0,0 +1,16 @@ +class IndexQaLocalAuthorityEntriesOnLowerLabel < ActiveRecord::Migration[5.1] + + # ActiveRecord doesn't support functional indexes, so we need to add this the old fashioned way. Note the different + # syntax for sqlite vs postgres + def up + if ActiveRecord::Base.connection.adapter_name.downcase.start_with? 'sqlite' + execute 'CREATE INDEX "index_qa_local_authority_entries_on_lower_label" ON "qa_local_authority_entries" (local_authority_id, label collate nocase);' + else + execute 'CREATE INDEX "index_qa_local_authority_entries_on_lower_label" ON "qa_local_authority_entries" (local_authority_id, lower(label));' + end + end + + def down + execute "DROP INDEX index_qa_local_authority_entries_on_lower_label;" + end +end diff --git a/hyrax/db/migrate/20191125140832_add_employee_type_code_to_users.rb b/hyrax/db/migrate/20191125140832_add_employee_type_code_to_users.rb new file mode 100644 index 00000000..97f82dcf --- /dev/null +++ b/hyrax/db/migrate/20191125140832_add_employee_type_code_to_users.rb @@ -0,0 +1,6 @@ +class AddEmployeeTypeCodeToUsers < ActiveRecord::Migration[5.1] + def change + add_column :users, :employee_type_code, :string + add_index :users, :employee_type_code + end +end diff --git a/hyrax/db/migrate/20200108111832_add_user_identifier_to_users.rb b/hyrax/db/migrate/20200108111832_add_user_identifier_to_users.rb new file mode 100644 index 00000000..83545c86 --- /dev/null +++ b/hyrax/db/migrate/20200108111832_add_user_identifier_to_users.rb @@ -0,0 +1,6 @@ +class AddUserIdentifierToUsers < ActiveRecord::Migration[5.1] + def change + add_column :users, :user_identifier, :string #, null: false + add_index :users, :user_identifier, unique: true + end +end diff --git a/hyrax/db/schema.rb b/hyrax/db/schema.rb index ec84a43e..176801ff 100644 --- a/hyrax/db/schema.rb +++ b/hyrax/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180501065341) do +ActiveRecord::Schema.define(version: 20200108111832) do create_table "bookmarks", force: :cascade do |t| t.integer "user_id", null: false @@ -279,6 +279,7 @@ t.string "uri" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["local_authority_id", "label"], name: "index_qa_local_authority_entries_on_lower_label" t.index ["local_authority_id"], name: "index_qa_local_authority_entries_on_local_authority_id" t.index ["uri"], name: "index_qa_local_authority_entries_on_uri", unique: true end @@ -543,8 +544,18 @@ t.binary "zotero_token" t.string "zotero_userid" t.string "preferred_locale" - t.index ["email"], name: "index_users_on_email", unique: true + t.string "username" + t.integer "failed_attempts", default: 0, null: false + t.string "unlock_token" + t.datetime "locked_at" + t.string "remember_token" + t.string "employee_type_code" + t.string "user_identifier" + t.index ["email"], name: "index_users_on_email" + t.index ["employee_type_code"], name: "index_users_on_employee_type_code" t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + t.index ["user_identifier"], name: "index_users_on_user_identifier", unique: true + t.index ["username"], name: "index_users_on_username", unique: true end create_table "version_committers", force: :cascade do |t| diff --git a/hyrax/docker-entrypoint.sh b/hyrax/docker-entrypoint.sh new file mode 100644 index 00000000..d7661310 --- /dev/null +++ b/hyrax/docker-entrypoint.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +echo "Creating log folder" +mkdir -p $APP_WORKDIR/log + +if [ "$RAILS_ENV" = "production" ]; then + # Verify all the production gems are installed + bundle check +else + # install any missing development gems (as we can tweak the development container without rebuilding it) + bundle check || bundle install --without production +fi + +# wait for Solr and Fedora to come up +sleep 15s + +## Run any pending migrations, if the database exists +## If not setup the database +bundle exec rake db:exists && bundle exec rake db:migrate || bundle exec rake db:setup + +# check that Solr is running +SOLR=$(curl --silent --connect-timeout 45 "http://${SOLR_HOST:-solr}:${SOLR_PORT:-8983}/solr/" | grep "Apache SOLR") +if [ -n "$SOLR" ] ; then + echo "Solr is running..." +else + echo "ERROR: Solr is not running" + exit 1 +fi + +# check that Fedora is running +FEDORA=$(curl --silent --connect-timeout 45 "http://${FEDORA_HOST:-fcrepo}:${FEDORA_PORT:-8080}/fcrepo/" | grep "Fedora Commons Repository") +if [ -n "$FEDORA" ] ; then + echo "Fedora is running..." +else + echo "ERROR: Fedora is not running" + exit 1 +fi + +echo "Setting up hyrax... (this can take a few minutes)" +bundle exec rake ngdr:setup_hyrax["seed/setup.json"] + +# echo "--------- Starting Hyrax in $RAILS_ENV mode ---------" +rm -f /tmp/hyrax.pid +bundle exec rails server -p 3000 -b '0.0.0.0' --pid /tmp/hyrax.pid diff --git a/hyrax/docs/container_diag.png b/hyrax/docs/container_diag.png new file mode 100644 index 00000000..a6b9792a Binary files /dev/null and b/hyrax/docs/container_diag.png differ diff --git a/hyrax/features/contact/contact.feature b/hyrax/features/contact/contact.feature new file mode 100644 index 00000000..7861b76c --- /dev/null +++ b/hyrax/features/contact/contact.feature @@ -0,0 +1,31 @@ +Feature: Contact form + + Background: + Given an initialised system with a default admin set, permission template and workflow + + Scenario: Unauthenticated user can edit name and email in the contact form + When I navigate to the contact form + Then I should see the contact form + And Name field is not readonly + And Email field is not readonly + + Scenario: nims_other user cannot edit name and email in the contact form + Given I am logged in as a nims_other user + When I navigate to the contact form + Then I should see the contact form + But Name field is readonly + And Email field is readonly + + Scenario: nims_researcher user cannot edit name and email in the contact form + Given I am logged in as a nims_researcher user + When I navigate to the contact form + Then I should see the contact form + But Name field is readonly + And Email field is readonly + + Scenario: Admin user cannot edit name and email in the contact form + Given I am logged in as an admin user + When I navigate to the contact form + Then I should see the contact form + But Name field is readonly + And Email field is readonly diff --git a/hyrax/features/datasets/catalog.feature b/hyrax/features/datasets/catalog.feature new file mode 100644 index 00000000..d822488f --- /dev/null +++ b/hyrax/features/datasets/catalog.feature @@ -0,0 +1,64 @@ +Feature: Datasets catalog index + + Background: + Given an initialised system with a default admin set, permission template and workflow + And there is 1 open dataset + And there are 2 authenticated datasets + And there is 1 restricted dataset + # NB: "restricted" means "private" in the user interface + + Scenario: Unauthenticated user can only view open datasets + When I navigate to the dataset catalog page + Then I should see the open datasets + And I should see only the public metadata of the open datasets + But I should not see the authenticated datasets + And I should not see the restricted dataset + + Scenario: Non-researcher user can view open and authenticated datasets + Given I am logged in as a nims_other user + When I navigate to the dataset catalog page + Then I should see the open datasets + And I should see the authenticated datasets + And I should see both the public and restricted metadata of the open datasets + And I should see both the public and restricted metadata of the authenticated datasets + But I should not see the restricted dataset + + Scenario: Researcher user can view open and authenticated datasets + Given I am logged in as a nims_researcher user + When I navigate to the dataset catalog page + Then I should see the open datasets + And I should see the authenticated datasets + And I should see both the public and restricted metadata of the open datasets + And I should see both the public and restricted metadata of the authenticated datasets + But I should not see the restricted dataset + + Scenario: Admin user can view open, authenticated and restricted datasets + Given I am logged in as an admin user + When I navigate to the dataset catalog page + Then I should see the open datasets + And I should see the authenticated datasets + And I should see the restricted dataset + And I should see both the public and restricted metadata of the open datasets + And I should see both the public and restricted metadata of the authenticated datasets + And I should see both the public and restricted metadata of the restricted datasets + +#Feature: データセット一覧を参照する +# 現在登録されているユーザを確認するため +# +# Scenario: 非ログインユーザがデータセット一覧を表示する +# Given ログインしない +# Given データが5件登録されている +# When データセット一覧画面を開く +# Then データが5件とも表示されない +# +# Scenario: 一般ユーザがデータセット一覧を表示する +# Given 一般ユーザでログインする +# Given データが5件登録されている +# When データセット一覧画面を開く +# Then データが5件表示される +# +# Scenario: 管理者ユーザがデータセット一覧を表示する +# Given 管理者でログインする +# Given データが5件登録されている +# When データセット一覧画面を開く +# Then データが5件表示される diff --git a/hyrax/features/datasets/create.feature b/hyrax/features/datasets/create.feature new file mode 100644 index 00000000..8e9fe8da --- /dev/null +++ b/hyrax/features/datasets/create.feature @@ -0,0 +1,19 @@ +Feature: Create a dataset + + Background: + Given an initialised system with a default admin set, permission template and workflow + + Scenario: Cannot create a dataset as a Non-Researcher user + Given I am logged in as a nims_other user + And I have permission to deposit + When I try to navigate to the new dataset page + Then I should not be authorized to access the page + + Scenario: Create a dataset as a NIMS Researcher user + Given I am logged in as a nims_researcher user + And I have permission to deposit + When I navigate to the new dataset page + And I create the dataset with: + | TITLE | SUPERVISOR | DATA_ORIGIN | CREATOR | KEYWORD | + | My Test Dataset | Jones, Janet | experiments | Doe, Jane | big data | + Then I should see a message that my files are being processed diff --git a/hyrax/features/datasets/search_links.feature b/hyrax/features/datasets/search_links.feature new file mode 100644 index 00000000..f33cde97 --- /dev/null +++ b/hyrax/features/datasets/search_links.feature @@ -0,0 +1,34 @@ +Feature: Search links on a dataset + Background: + Given an initialised system with a default admin set, permission template and workflow + And there is a dataset with: + | TRAIT | + | open | + | with_complex_person | + | with_complex_author | + | with_complex_chemical_composition | + | with_complex_crystallographic_structure | + | with_custom_property | + | with_complex_date | + | with_complex_identifier | + | with_complex_instrument | + | with_complex_specimen_type | + | with_complex_relation | + | with_complex_rights | + | with_complex_version | + + + Scenario: Search links are generated correctly + Given I am on the dataset page + Then I should see the following links: + | LABEL | HREF | + | Anamika | /catalog?f%5Bcomplex_person_sim%5D%5B%5D=Anamika | + | University | /catalog?f%5Bcomplex_person_organization_sim%5D%5B%5D=University | + | Instrument title | /catalog?f%5Bcomplex_instrument_sim%5D%5B%5D=Instrument+title | + | Foo | /catalog?f%5Binstrument_manufacturer_sim%5D%5B%5D=Foo | + | Name of operator | /catalog?f%5Bcomplex_person_operator_sim%5D%5B%5D=Name+of+operator | + | University | /catalog?f%5Bcomplex_person_operator_organization_sim%5D%5B%5D=University | + | Managing organization name | /catalog?f%5Binstrument_managing_organization_sim%5D%5B%5D=Managing+organization+name | + | Purchase record title | /catalog?f%5Bcomplex_purchase_record_title_sim%5D%5B%5D=Purchase+record+title | + | Fooss | /catalog?f%5Bcomplex_purchase_record_supplier_sim%5D%5B%5D=Fooss | + | Foo | /catalog?f%5Bcomplex_purchase_record_manufacturer_sim%5D%5B%5D=Foo | diff --git a/hyrax/features/step_definitions/.gitkeep b/hyrax/features/step_definitions/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/hyrax/features/step_definitions/contact_steps.rb b/hyrax/features/step_definitions/contact_steps.rb new file mode 100644 index 00000000..c69be310 --- /dev/null +++ b/hyrax/features/step_definitions/contact_steps.rb @@ -0,0 +1,23 @@ +When("I navigate to the contact form") do + visit '/contact' +end + +Then("I should see the contact form") do + expect(page).to have_content('Contact Form') +end + +Then("Name field is not readonly") do + expect(page).to have_field('Your Name', type: 'text', readonly: false) +end + +Then("Email field is not readonly") do + expect(page).to have_field('Your Email', type: 'text', readonly: false) +end + +Then("Name field is readonly") do + expect(page).to have_field('Your Email', type: 'text', readonly: true) +end + +Then("Email field is readonly") do + expect(page).to have_field('Your Email', type: 'text', readonly: true) +end diff --git a/hyrax/features/step_definitions/dataset_steps.rb b/hyrax/features/step_definitions/dataset_steps.rb new file mode 100644 index 00000000..e375ebf5 --- /dev/null +++ b/hyrax/features/step_definitions/dataset_steps.rb @@ -0,0 +1,132 @@ +Given(/^there (?:are|is) (\d+) (open|authenticated|embargo|lease|restricted) datasets?$/) do |number, access| + @datasets ||= {} + @datasets[access] = FactoryBot.create_list(:dataset, number, access.to_sym, :with_description_seq, :with_keyword_seq, :with_subject_seq).each do |obj| + ActiveFedora::SolrService.add(obj.to_solr) + end + ActiveFedora::SolrService.commit +end + +Given(/^there is a dataset with:$/) do |table| + @dataset = FactoryBot.create(:dataset, *table.rows.flatten.map(&:to_sym)) + ActiveFedora::SolrService.add(@dataset.to_solr) + ActiveFedora::SolrService.commit +end + +Given(/^I am on the dataset page$/) do + visit hyrax_dataset_path(@dataset) +end + +When(/^I navigate to the new dataset page$/) do + visit hyrax.dashboard_path # /dashboard + click_link "Works" + click_link "Add new work" + + # If you generate more than one work uncomment these lines + choose "payload_concern", option: "Dataset" + click_button "Create work" + + # small hack to skip to create dataset page without requiring javascript + visit new_hyrax_dataset_path +end + +When /^I try to navigate to the new dataset page$/ do + visit new_hyrax_dataset_path +end + +When(/^I navigate to the dataset catalog page$/) do + visit root_path + click_link 'Browse all datasets' + # visit search_catalog_path('f[human_readable_type_sim][]' => 'Dataset') +end + +When(/^I create the dataset with:$/) do |table| + values = table.hashes.first # table is a table.hashes.keys # => [:TITLE, :SUPERVISOR, :DATA_ORIGIN, :CREATOR, :KEYWORD] + + expect(page).to have_content /Add New Dataset/i + + click_link "Files" # switch tab + expect(page).to have_content /Add files/i + expect(page).to have_content /Add folder/i + within('span#addfiles') do + attach_file("files[]", "#{Hyrax::Engine.root}/spec/fixtures/image.jp2", visible: false) + attach_file("files[]", "#{Hyrax::Engine.root}/spec/fixtures/jp2_fits.xml", visible: false) + end + + click_link "Descriptions" # switch tab + fill_in('Title', with: values[:TITLE]) + fill_in('Supervisor', with: values[:SUPERVISOR]) + select(values[:DATA_ORIGIN], from: 'Data origin') + fill_in('dataset[complex_person_attributes][0][name][]', with: values[:CREATOR]) + fill_in('Keyword', with: values[:KEYWORD]) + select('Creative Commons BY-SA Attribution-ShareAlike 4.0 International', from: 'dataset[complex_rights_attributes][0][rights][]') + + # With selenium and the chrome driver, focus remains on the + # select box. Click outside the box so the next line can't find + # its element + find('body').click + choose('dataset_visibility_open') + expect(page).to have_content('Please note, making something visible to the world (i.e. marking this as Public) may be viewed as publishing which could impact your ability to') + check('agreement') + + click_on('Save') + + expect(page).to have_content(values[:TITLE]) +end + +Then(/^I should see the (open|authenticated|embargo|lease|restricted) datasets?$/) do |access| + # first, verify @datasets is present and has some data + expect(@datasets[access]).to be_present + + # next, verify there is a link to each dataset (using a regular expression to allow for the locale parameter) + @datasets[access].each do |dataset| + expect(page).to have_link(dataset.title.first, href: Regexp.new(hyrax_dataset_path(dataset))) + end +end + +Then(/^I should not see the (open|authenticated|embargo|lease|restricted) datasets?$/) do |access| + # first, verify @datasets is present and has some data + expect(@datasets[access]).to be_present + + # next, verify there is a link to each dataset (using a regular expression to allow for the locale parameter) + @datasets[access].each do |dataset| + expect(page).to_not have_link(dataset.title.first, href: Regexp.new(hyrax_dataset_path(dataset))) + end +end + +Then(/^I should see only the public metadata of the (open|authenticated|embargo|lease|restricted) datasets?$/) do |access| + # first, verify @datasets is present and has some data + expect(@datasets[access]).to be_present + + @datasets[access].each do |dataset| + # check public metadata is visible + [:subject, :keyword].each do |field| + expect(page).to have_css('div.metadata dl dt', text: Regexp.new(field.to_s, Regexp::IGNORECASE)) + expect(page).to have_css('div.metadata dl dd', text: dataset.send(field).first) + end + + # check restricted metadata is not visible + [:description].each do |field| + expect(page).not_to have_css('div.metadata dl dt', text: Regexp.new(field.to_s, Regexp::IGNORECASE)) + expect(page).not_to have_css('div.metadata dl dd', text: dataset.send(field).first) + end + end +end + +Then(/^I should see both the public and restricted metadata of the (open|authenticated|embargo|lease|restricted) datasets?$/) do |access| + # first, verify @datasets is present and has some data + expect(@datasets[access]).to be_present + + @datasets[access].each do |dataset| + # check public and restricted metadata is visible + [:description, :subject, :keyword].each do |field| + expect(page).to have_css('div.metadata dl dt', text: Regexp.new(field.to_s, Regexp::IGNORECASE)) + expect(page).to have_css('div.metadata dl dd', text: dataset.send(field).first) + end + end +end + +Then(/^I should see the following links:$/) do |table| + table.symbolic_hashes.each do |row| + expect(page).to have_link(row[:label], href: Regexp.new(Regexp.quote(row[:href]))) + end +end diff --git a/hyrax/features/step_definitions/initial_steps.rb b/hyrax/features/step_definitions/initial_steps.rb new file mode 100644 index 00000000..a0f6ebf2 --- /dev/null +++ b/hyrax/features/step_definitions/initial_steps.rb @@ -0,0 +1,6 @@ +Given(/^an initialised system with a default admin set, permission template and workflow$/) do + @admin_set_id = AdminSet.find_or_create_default_admin_set_id + @permission_template = Hyrax::PermissionTemplate.find_or_create_by!(source_id: @admin_set_id) + @workflow = Sipity::Workflow.create!(active: true, name: 'test-workflow', permission_template: @permission_template) + Sipity::WorkflowAction.create!(name: 'submit', workflow: @workflow) +end diff --git a/hyrax/features/step_definitions/permission_steps.rb b/hyrax/features/step_definitions/permission_steps.rb new file mode 100644 index 00000000..fd968450 --- /dev/null +++ b/hyrax/features/step_definitions/permission_steps.rb @@ -0,0 +1,12 @@ +Given(/^I have permission to (view|deposit|manage)$/) do |access| + fail '@permission_template must be defined before running this step' unless @permission_template.present? + fail '@user must be defined before running this step' unless @user.present? + + # Grant the user access to deposit into the admin set + Hyrax::PermissionTemplateAccess.create!( + permission_template_id: @permission_template.id, + agent_type: 'user', + agent_id: @user.user_key, + access: access + ) +end diff --git a/hyrax/features/step_definitions/user_steps.rb b/hyrax/features/step_definitions/user_steps.rb new file mode 100644 index 00000000..cc043756 --- /dev/null +++ b/hyrax/features/step_definitions/user_steps.rb @@ -0,0 +1,51 @@ +include Warden::Test::Helpers + +Given(/^an? (guest|nims_other|nims_researcher|admin) user$/) do |user_type| + @user = FactoryBot.create(:user, user_type.to_sym) +end + +Given(/^I am logged in$/) do + login_as @user +end + +Given(/^I am logged in as an? (guest|nims_other|nims_researcher|admin) user$/) do |user_type| + step "a #{user_type} user" + step 'I am logged in' +end + +Given(/^there (?:are|is) (\d+) (guest|nims_other|nims_researcher|admin) users?$/) do |number, user_type| + @users ||= {} + @users[user_type] = FactoryBot.create_list(:user, number, user_type.to_sym) +end + +When(/^I navigate to the users list$/) do + visit hyrax.users_path +end + +Then(/^I should see the (guest|nims_other|nims_researcher|admin) users?$/) do |user_type| + # first, verify @users is present and has some data + expect(@users[user_type]).to be_present + + # next, verify there is a link to each dataset (using a regular expression to allow for the locale parameter) + @users[user_type].each do |user| + expect(page).to have_link(user.username, href: Regexp.new(hyrax.user_path(user))) + end +end + +Then(/^I should not see the (guest|nims_other|nims_researcher|admin) users?$/) do |user_type| + # first, verify @users is present and has some data + expect(@users[user_type]).to be_present + + # next, verify there is a link to each dataset (using a regular expression to allow for the locale parameter) + @users[user_type].each do |user| + expect(page).to_not have_link(user.username, href: Regexp.new(hyrax.user_path(user))) + end +end + +Then(/^I should be redirected to the login page$/) do + expect(current_path).to eql(new_user_session_path) +end + +Then(/^I should be redirected to the home page$/) do + expect(current_path).to eql(root_path) +end diff --git a/hyrax/features/step_definitions/users_steps.rb b/hyrax/features/step_definitions/users_steps.rb new file mode 100644 index 00000000..22a91e44 --- /dev/null +++ b/hyrax/features/step_definitions/users_steps.rb @@ -0,0 +1,20 @@ +When("I navigate to the user list page") do + visit '/users' +end + +Then("I should not see the user list") do + expect(page).not_to have_content 'Search Users' +end + +Then("I should get 'need to sign in'") do + expect(page).to have_content 'You need to sign in or sign up before continuing.' +end + +Then("I should get 'not authorized'") do + expect(page).to have_content 'You are not authorized to access this page.' +end + +Then("I should see the user list") do + expect(@user.admin?).to be_truthy + expect(page).to have_content 'Search Users' +end diff --git a/hyrax/features/step_definitions/work_steps.rb b/hyrax/features/step_definitions/work_steps.rb new file mode 100644 index 00000000..edd0a271 --- /dev/null +++ b/hyrax/features/step_definitions/work_steps.rb @@ -0,0 +1,11 @@ +Then(/^I should see a message that my files are being processed$/) do + expect(page).to have_content "Your files are being processed by MDR in the background." +end + +Then(/^I should see no results found$/) do + expect(page).to have_content 'No results found for your search' +end + +Then(/^I should not be authorized to access the page$/) do + expect(page).to have_content "You are not authorized to access this page." +end diff --git a/hyrax/features/support/after_hook.rb b/hyrax/features/support/after_hook.rb new file mode 100644 index 00000000..5e2cf62a --- /dev/null +++ b/hyrax/features/support/after_hook.rb @@ -0,0 +1,3 @@ +After do |scenario| + Dataset.destroy_all if ENV['RAILS_ENV'] == 'test' +end diff --git a/hyrax/features/support/env.rb b/hyrax/features/support/env.rb new file mode 100644 index 00000000..003fb131 --- /dev/null +++ b/hyrax/features/support/env.rb @@ -0,0 +1,60 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + +require 'cucumber/rails' + +# frozen_string_literal: true + +# Capybara defaults to CSS3 selectors rather than XPath. +# If you'd prefer to use XPath, just uncomment this line and adjust any +# selectors in your step definitions to use the XPath syntax. +# Capybara.default_selector = :xpath + +# By default, any exception happening in your Rails application will bubble up +# to Cucumber so that your scenario will fail. This is a different from how +# your application behaves in the production environment, where an error page will +# be rendered instead. +# +# Sometimes we want to override this default behaviour and allow Rails to rescue +# exceptions and display an error page (just like when the app is running in production). +# Typical scenarios where you want to do this is when you test your error pages. +# There are two ways to allow Rails to rescue exceptions: +# +# 1) Tag your scenario (or feature) with @allow-rescue +# +# 2) Set the value below to true. Beware that doing this globally is not +# recommended as it will mask a lot of errors for you! +# +ActionController::Base.allow_rescue = false + +# Remove/comment out the lines below if your app doesn't have a database. +# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead. +begin + DatabaseCleaner.strategy = :transaction +rescue NameError + raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it." +end + +# You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios. +# See the DatabaseCleaner documentation for details. Example: +# +# Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do +# # { except: [:widgets] } may not do what you expect here +# # as Cucumber::Rails::Database.javascript_strategy overrides +# # this setting. +# DatabaseCleaner.strategy = :truncation +# end +# +# Before('not @no-txn', 'not @selenium', 'not @culerity', 'not @celerity', 'not @javascript') do +# DatabaseCleaner.strategy = :transaction +# end +# + +# Possible values are :truncation and :transaction +# The :transaction strategy is faster, but might give you threading problems. +# See https://github.com/cucumber/cucumber-rails/blob/master/features/choose_javascript_database_strategy.feature +Cucumber::Rails::Database.javascript_strategy = :truncation + diff --git a/hyrax/features/users/index.feature b/hyrax/features/users/index.feature new file mode 100644 index 00000000..c73df8bb --- /dev/null +++ b/hyrax/features/users/index.feature @@ -0,0 +1,47 @@ +Feature: Users index page + + Background: + Given there are 3 nims_researcher users + + Scenario: Unauthenticated user cannot view users + When I navigate to the users list + Then I should not see the nims_researcher users + And I should be redirected to the login page + + Scenario: nims_other user cannot view users + Given I am logged in as an nims_other user + When I navigate to the users list + Then I should not see the nims_researcher users + And I should be redirected to the home page + + Scenario: nims_researcher user cannot view users + Given I am logged in as an nims_researcher user + When I navigate to the users list + Then I should not see the nims_researcher users + And I should be redirected to the home page + + Scenario: Admin user can view users + Given I am logged in as an admin user + When I navigate to the users list + Then I should see the nims_researcher users + +#Feature: ユーザ一覧を参照する +#現在登録されているユーザを確認するため +# +# Scenario: 非ログインユーザがユーザ一覧を表示する +# Given ログインしない +# Given ユーザが5件登録されている +# When ユーザ一覧画面を開く +# Then ユーザが5件とも表示されない +# +# Scenario: 一般ユーザがユーザ一覧を表示する +# Given 一般ユーザでログインする +# Given ユーザが5件登録されている +# When ユーザ一覧画面を開く +# Then ユーザが5件表示される +# +# Scenario: 管理者ユーザがユーザ一覧を表示する +# Given 管理者でログインする +# Given ユーザが5件登録されている +# When ユーザ一覧画面を開く +# Then ユーザが5件表示される diff --git a/hyrax/lib/importers/collection_importer.rb b/hyrax/lib/importers/collection_importer.rb new file mode 100644 index 00000000..a627995c --- /dev/null +++ b/hyrax/lib/importers/collection_importer.rb @@ -0,0 +1,55 @@ +module Importers + class CollectionImporter + + attr_accessor :col_id + + def initialize(attributes, col_id=nil, visibility='open') + @col_id = col_id ||= ::Noid::Rails::Service.new.minter.mint + @visibility = check_visibility(visibility) + @attributes = attributes + @user_collection = find_user_collection + end + + def fetch_collection + begin + Collection.find(@col_id) + rescue ActiveFedora::ObjectNotFoundError + nil + end + end + + def create_collection + if fetch_collection.blank? + return unless @attributes.any? + set_attributes + collection = Collection.new(@attributes) + collection.reindex_extent = Hyrax::Adapters::NestingIndexAdapter::LIMITED_REINDEX + collection.save! + # collection.update_index + collection + end + end + + private + def set_attributes + @attributes[:id] = @col_id + @attributes[:collection_type] = @user_collection + @attributes[:visibility] = @visibility unless @visibility.blank? + end + + def check_visibility(visibility) + # Filesets inherit visibility for work + possible_options = %w(open authenticated embargo lease restricted) + return nil unless possible_options.include? visibility + visibility + end + + def find_user_collection + user_col = nil + Hyrax::CollectionType.all.each do |col| + user_col = col if col.user_collection? + end + user_col + end + end +end diff --git a/hyrax/lib/importers/dataset_importer.rb b/hyrax/lib/importers/dataset_importer.rb new file mode 100644 index 00000000..a4c128cb --- /dev/null +++ b/hyrax/lib/importers/dataset_importer.rb @@ -0,0 +1,11 @@ +require 'nokogiri' +require 'importers/hyrax_importer' + +module Importers + module DatasetImporter + require 'importers/dataset_importer/parse_xml' + require 'importers/dataset_importer/unpacker' + require 'importers/dataset_importer/importer' + require 'importers/dataset_importer/bulk_importer' + end +end diff --git a/hyrax/lib/importers/dataset_importer/bulk_importer.rb b/hyrax/lib/importers/dataset_importer/bulk_importer.rb new file mode 100644 index 00000000..2d1b8c45 --- /dev/null +++ b/hyrax/lib/importers/dataset_importer/bulk_importer.rb @@ -0,0 +1,66 @@ +module Importers + module DatasetImporter + class BulkImporter + + attr_accessor :import_dir, :metadata_filename, :collections, :debug + + def initialize(import_dir, metadata_filename=nil, collections=nil, debug=false) + @import_dir = import_dir + @metadata_filename = metadata_filename + @collections = collections + @debug = debug + @log_file = get_log_file + @count = 0 + end + + def perform_create + raise StandardError, "Import directory not found" unless File.directory?(import_dir) + Dir.glob(File.join(import_dir, '*')).each do |dir| + puts "Starting on #{dir}" + begin + importer = Importers::DatasetImporter::Importer.new(dir, @metadata_filename, @collections, @debug) + importer.perform_create + log_progress(dir, importer.attributes, importer.files, importer.errors, importer.time_taken) + rescue StandardError => exception + puts exception.backtrace.unshift(exception.message) + end + @count += 1 + end + end + + private + + def log_rotate + get_log_file if @log_file.blank? or (@count % 1000 == 0) + end + + def get_log_file + @log_file = "data/#{Time.now.strftime('%Y-%m-%d-%H-%M-%S')}_import_dataset_log.csv" + end + + def log_progress(dir, attributes, files, error, time_taken) + write_headers = true + write_headers = false if File.file?(@log_file) + csv_file = CSV.open(@log_file, "ab") + csv_file << [ + 'Current time', + 'Directory', + 'attributes', + 'files', + 'error', + 'time taken' + ] if write_headers + files = '' if files.blank? + csv_file << [ + Time.now.to_s, + dir, + JSON.pretty_generate(attributes), + JSON.pretty_generate(files), + JSON.pretty_generate(error), + time_taken.to_s + ] + csv_file.close + end + end + end +end diff --git a/hyrax/lib/importers/dataset_importer/importer.rb b/hyrax/lib/importers/dataset_importer/importer.rb new file mode 100644 index 00000000..81ea2542 --- /dev/null +++ b/hyrax/lib/importers/dataset_importer/importer.rb @@ -0,0 +1,38 @@ +module Importers + module DatasetImporter + class Importer + include Importers::DatasetImporter::Unpacker + include Importers::DatasetImporter::ParseXml + + attr_reader :import_dir, :metadata_file, :title, :files, :attributes, :errors, :time_taken + + def initialize(import_dir, metadata_filename=nil, collection_ids=nil, debug=false) + @import_dir = import_dir + @metadata_filename = metadata_filename + @collection_ids = collection_ids + @debug = debug + @metadata_file = nil + @title = nil + @files = [] + @attributes = {} + @errors = [] + end + + def perform_create + start_time = Time.now + unpack_dataset + parse_metadata + unless @debug + h = Importers::HyraxImporter.new('Dataset', attributes, files, @collection_ids) + begin + h.import + rescue StandardError => exception + @errors << exception.backtrace.unshift(exception.message) + end + end + @time_taken = Time.now - start_time + end + + end + end +end diff --git a/hyrax/lib/importers/dataset_importer/parse_xml.rb b/hyrax/lib/importers/dataset_importer/parse_xml.rb new file mode 100644 index 00000000..037000b4 --- /dev/null +++ b/hyrax/lib/importers/dataset_importer/parse_xml.rb @@ -0,0 +1,616 @@ +module Importers + module DatasetImporter + module ParseXml + + def parse_metadata + @xml_metadata = File.open(@metadata_file) { |f| Nokogiri::XML(f) { |conf| conf.noblanks } } + @xml_metadata.remove_namespaces! + get_basic_data_description + get_specimen_description + get_instrument_description + get_specimen_types + get_characterization_methods + end + + private + + def get_basic_data_description + desc = @xml_metadata.xpath("depositUploadReq/common-term/basic-data-description") + get_persistent_identifiers(desc) + get_local_identifiers(desc) + get_stakeholders(desc) + get_organization(desc) + get_project_id(desc) + get_data_history(desc) + get_data_origin(desc) + get_license(desc) + get_visibility(desc) + get_title + # set_title + end + + def get_specimen_description + #TODO: NIMS to get back on this + end + + def get_instrument_description + parent = 'complex_instrument' + ele = @xml_metadata.xpath('depositUploadReq/common-term/instrument-description') + ele.each do |inst| + inst_hash = {} + get_instrument_identifiers(inst, inst_hash) + get_instrument_name(inst, inst_hash) + get_instrument_manufacturer(inst, inst_hash) + get_instrument_type(inst, inst_hash) + get_instrument_managing_organization(inst, inst_hash) + get_instrument_category_code(inst, inst_hash) + get_instrument_sub_category_code(inst, inst_hash) + get_instrument_function(inst, inst_hash) + get_instrument_operator(inst, inst_hash) + get_instrument_process_date(inst, inst_hash) + assign_nested_hash(parent, inst_hash, false) if inst_hash.any? + end + end + + def get_specimen_types + parent = 'complex_specimen_type' + ele = @xml_metadata.xpath('depositUploadReq/domain-specific-term/specimen-types/type') + ele.each do |st| + st_hash = {} + get_specimen_type_persistent_identifiers(st, st_hash) + get_specimen_type_local_identifiers(st, st_hash) + get_specimen_type_name(st, st_hash) + get_specimen_type_description(st, st_hash) + get_specimen_type_crystallographic_structure(st, st_hash) + get_specimen_type_chemical_composition(st, st_hash) + get_specimen_type_structural_feature(st, st_hash) + get_specimen_type_material_type(st, st_hash) + get_specimen_type_purchase_record(st, st_hash) + get_specimen_type_shape(st, st_hash) + get_specimen_type_state_of_matter(st, st_hash) + assign_nested_hash(parent, st_hash, false) if st_hash.any? + end + end + + def get_characterization_methods + #TODO: This needs to be modelled + end + + def get_persistent_identifiers(ele) + vals = get_text(ele, "data-identifier/data-permanent-identifier") + vals.each do |val| + id = { + identifier: val, + scheme: 'identifier persistent', + } + parent = 'complex_identifier' + assign_nested_hash(parent, id, false) + end + end + + def get_local_identifiers(ele) + vals = get_text(ele, "data-identifier/data-local-identifier") + vals.each do |val| + id = { + identifier: val, + scheme: 'identifier local', + } + parent = 'complex_identifier' + assign_nested_hash(parent, id, false) + end + end + + def get_stakeholders(ele) + ele.xpath('stakeholders').children.each do |sh| + next unless sh.name.end_with? '-identifier' + person = get_person_hash(sh) + if person.any? + parent = 'complex_person' + assign_nested_hash(parent, person, false) + end + end + end + + def get_organization(ele) + org_ele = ele.xpath('organization') + org = get_organization_hash(org_ele) + if org.any? + parent = 'complex_organization' + assign_nested_hash(parent, org, false) + end + end + + def get_project_id(ele) + vals = get_text(ele, 'project/project-identifier') + if vals.any? + id = { + identifier: vals[0], + scheme: 'project id' + } + parent = 'complex_identifier' + assign_nested_hash(parent, id, false) + end + end + + def get_data_history(ele) + parent = 'complex_date' + # created date + vals = get_text(ele, 'data-history/created-date-at-origin') + if vals.any? + dt = { + date: vals[0], + description: 'http://purl.org/dc/terms/created' + } + assign_nested_hash(parent, dt, false) + end + # modified date + vals = get_text(ele, 'data-history/latest-modified-date-at-origin') + if vals.any? + dt = { + date: vals[0], + description: 'http://bibframe.org/vocab/changeDate' + } + assign_nested_hash(parent, dt, false) + end + # deposit date + vals = get_text(ele, 'data-history/deposit-to-core-date') + if vals.any? + dt = { + date: vals[0], + description: 'Deposited' + } + assign_nested_hash(parent, dt, false) + end + end + + def get_data_origin(ele) + vals = get_text(ele, 'data-origin') + if vals.any? + term = DataOriginService.new.find_by_id_or_label(vals[0]) + if term.any? + @attributes[:data_origin] = Array(term['id']) + else + @errors << "#{vals[0]} not in data origin authority" + end + end + end + + def get_license(ele) + vals = get_text(ele, 'licenses/license') + if vals.any? + term = RightsService.new.find_by_id_or_label(vals[0]) + if term.any? + @attributes[:license] = term['id'] + else + @errors << "#{vals[0]} not in license authority" + end + end + end + + def get_visibility(ele) + visibility_options = %w(open authenticated embargo lease restricted) + # TODO: Map all visibility options + visibility_map = { + 'public' => 'open' + } + vals = get_text(ele, 'visibility/visibility') + if vals.any? + visibility = nil + if visibility_map.include?(vals[0].downcase) + visibility = visibility_map[vals[0].downcase] + elsif visibility_options.include?(vals[0].downcase) + visibility = vals[0].downcase + end + @attributes[:visibility] = visibility if visibility.present? + end + end + + def get_title + filenames = [] + @xml_metadata.xpath("depositUploadReq/additional-attachment-pointer/additional-for-attached-filename[@attached-order='1']/object-path-name").each do |fp| + filenames << File.basename(fp.text.strip, '.zip') if fp.text + end + @attributes[:title] = [filenames[0]] if filenames.any? + end + + def set_title + @attributes[:title] = Array(@title) if @title.present? + end + + def get_instrument_identifiers(ele, inst_hash) + vals = get_text(ele, "identifier/local-identifier") + vals.each do |val| + id = { + identifier: val, + scheme: 'identifier local', + } + parent = 'complex_identifier' + assign_nested_hash(parent, id, false, inst_hash) + end + end + + def get_instrument_name(ele, inst_hash) + vals = get_text(ele, 'name') + inst_hash[:title] = vals[0] if vals.any? + end + + def get_instrument_manufacturer(ele, inst_hash) + org_ele = ele.xpath('manufacturer') + org = get_organization_hash(org_ele, 'Manufacturer') + if org.any? + parent = 'manufacturer' + assign_nested_hash(parent, org, false, inst_hash) + end + end + + def get_instrument_type(ele, inst_hash) + vals = get_text(ele, 'instrument-type') + inst_hash[:model_number] = vals[0] if vals.any? + end + + def get_instrument_managing_organization(ele, inst_hash) + org_ele = ele.xpath('managing-organization') + org = get_organization_hash(org_ele, 'Managing organization') + if org.any? + parent = 'managing_organization' + assign_nested_hash(parent, org, false, inst_hash) + end + end + + def get_instrument_category_code(ele, inst_hash) + #TODO: NIMS to get back on this + end + + def get_instrument_sub_category_code(ele, inst_hash) + # TODO: NIMS to get back on this + end + + def get_instrument_function(ele, inst_hash) + # TODO: NIMS to get back on this + # The xml is as follows + # + # + # + # + # + # 4 + # 0001** + # 0002** + # 0003** + # 0004** + # + # Instrument function has been modelled with the following fields + # column_number + # category + # sub_category + # description + end + + def get_instrument_operator(ele, inst_hash) + people_ele = ele.xpath('operator-identifier') + people_ele.each do |person_ele| + person = get_person_hash(person_ele) + if person.any? + parent = 'complex_person' + assign_nested_hash(parent, person, false, inst_hash) + end + end + end + + def get_instrument_process_date(ele, inst_hash) + vals = get_text(ele, 'process-date') + if vals.any? + dt = { + date: vals[0], + description: 'Processed' + } + parent = 'complex_date' + assign_nested_hash(parent, dt, false, inst_hash) + end + end + + def get_specimen_type_persistent_identifiers(ele, st_hash) + parent = 'complex_identifier' + vals = get_text(ele, "specimen-identifier/pid") + vals.each do |val| + id = { + identifier: val, + scheme: 'identifier persistent', + } + assign_nested_hash(parent, id, false, st_hash) + end + end + + def get_specimen_type_local_identifiers(ele, st_hash) + parent = 'complex_identifier' + vals = get_text(ele, "specimen-identifier/local-identifier") + vals.each do |val| + id = { + identifier: val, + scheme: 'identifier local', + } + assign_nested_hash(parent, id, false, st_hash) + end + end + + def get_specimen_type_name(ele, st_hash) + vals = get_text(ele, 'general-name') + st_hash[:title] = vals if vals.any? + end + + def get_specimen_type_description(ele, st_hash) + vals = get_text(ele, 'description') + st_hash[:description] = vals if vals.any? + end + + def get_specimen_type_crystallographic_structure(ele, st_hash) + # TODO: This is incomplete. NIMS to get back on this + vals_1 = get_text(ele, 'crystallographic-structure/code-type') + vals_2 = get_text(ele, 'crystallographic-structure/class') + vals = vals_1 + vals_2 + if vals.any? + cs_hash = { description: vals.join(' ') } + parent = 'complex_crystallographic_structure' + assign_nested_hash(parent, cs_hash, false, st_hash) + end + end + + def get_specimen_type_chemical_composition(ele, st_hash) + parent = 'complex_chemical_composition' + ele.xpath('chemical-composition').each do |cc| + cc_hash = {} + get_chemical_composition_identifier(cc, cc_hash) + get_chemical_composition_description(cc, cc_hash) + assign_nested_hash(parent, cc_hash, false, st_hash) if cc_hash.any? + end + end + + def get_chemical_composition_identifier(ele, cc_hash) + parent = 'complex_identifier' + ele.xpath('chemical-composition-identifier').each do |id| + vals = get_identifier_hash(id) + assign_nested_hash(parent, vals, false, cc_hash) if vals.any? + end + end + + def get_chemical_composition_description(ele, cc_hash) + vals = get_text(ele, 'chemical-composition-description') + cc_hash[:description] = vals[0] if vals.any? + end + + def get_specimen_type_structural_feature(ele, st_hash) + parent = 'complex_structural_feature' + ele.xpath('structural-features').each do |sf| + sf_hash = {} + get_structural_feature_identifier(sf, sf_hash) + get_structural_feature_description(sf, sf_hash) + get_structural_feature_category(sf, sf_hash) + get_structural_feature_sub_category(sf, sf_hash) + assign_nested_hash(parent, sf_hash, false, st_hash) if sf_hash.any? + end + end + + def get_structural_feature_identifier(ele, sf_hash) + parent = 'complex_identifier' + ele.xpath('structural-features-identifier').each do |id| + vals = get_identifier_hash(id) + assign_nested_hash(parent, vals, false, sf_hash) if vals.any? + end + end + + def get_structural_feature_description(ele, sf_hash) + vals = get_text(ele, 'structural-features-description') + sf_hash[:description] = vals[0] if vals.any? + end + + def get_structural_feature_category(ele, sf_hash) + vals = get_text(ele, 'structural-features-category') + sf_hash[:category] = vals[0] if vals.any? + end + + def get_structural_feature_sub_category(ele, sf_hash) + vals = get_text(ele, 'structural-features-subcategory') + sf_hash[:sub_category] = vals[0] if vals.any? + end + + def get_specimen_type_material_type(ele, st_hash) + parent = 'complex_material_type' + ele.xpath('material-type').each do |mt| + mt_hash = {} + get_material_type_identifier(mt, mt_hash) + get_material_type_description(mt, mt_hash) + get_material_type_material_type(mt, mt_hash) + get_material_type_material_sub_type(mt, mt_hash) + assign_nested_hash(parent, mt_hash, false, st_hash) if mt_hash.any? + end + end + + def get_material_type_identifier(ele, mt_hash) + parent = 'complex_identifier' + ele.xpath('material-type-identifier').each do |id| + vals = get_identifier_hash(id) + assign_nested_hash(parent, vals, false, mt_hash) if vals.any? + end + end + + def get_material_type_description(ele, mt_hash) + # description + vals = get_text(ele, 'material-type-description') + mt_hash[:description] = vals[0] if vals.any? + end + + def get_material_type_material_type(ele, mt_hash) + vals = get_text(ele, 'material-type') + mt_hash[:material_type] = vals[0] if vals.any? + end + + def get_material_type_material_sub_type(ele, mt_hash) + vals = get_text(ele, 'sub-material-type') + mt_hash[:material_sub_type] = vals[0] if vals.any? + end + + def get_specimen_type_purchase_record(ele, st_hash) + parent = 'complex_purchase_record' + ele.xpath('purchase').each do |pr| + pr_hash = {} + get_purchase_record_date(pr, pr_hash) + get_purchase_record_identifier(pr, pr_hash) + get_purchase_record_supplier(pr, pr_hash) + get_purchase_record_manufacturer(pr, pr_hash) + assign_nested_hash(parent, pr_hash, false, st_hash) if pr_hash.any? + end + end + + def get_purchase_record_date(ele, pr_hash) + vals = get_text(ele, 'purchase-date') + pr_hash[:date] = vals if vals.any? + end + + def get_purchase_record_identifier(ele, pr_hash) + parent = 'complex_identifier' + vals = get_text(ele, "lot-identifier") + vals.each do |val| + id = { + identifier: val, + scheme: 'identifier local', + } + assign_nested_hash(parent, id, false, pr_hash) + end + end + + def get_purchase_record_supplier(ele, pr_hash) + parent = 'supplier' + org_ele = ele.xpath('supplier') + org = get_organization_hash(org_ele, 'Supplier') + if org.any? + assign_nested_hash(parent, org, false, pr_hash) + end + end + + def get_purchase_record_manufacturer(ele, pr_hash) + parent = 'manufacturer' + org_ele = ele.xpath('item/manufacturer') + org = get_organization_hash(org_ele, 'Manufacturer') + if org.any? + assign_nested_hash(parent, org, false, pr_hash) + end + end + + def get_specimen_type_shape(ele, st_hash) + # TODO: NIMS to get back on this + # The xml is as follows + # + # form + # plate + # + # + # form + # solid + # + # complex_shape has been modelled with the following fields + # complex_identifier + # description + end + + def get_specimen_type_state_of_matter(ele, st_hash) + # TODO: NIMS to get back on this + # The xml is as follows + # + # form + # plate + # + # + # form + # solid + # + # complex_state_of_matter has been modelled with the following fields + # complex_identifier + # description + end + + # ================================= + # helpful methods + # ================================= + + def get_text(node, element) + values = [] + node.search("./#{element}").each do |ele| + values << ele.text.strip if ele.text + end + values.reject { |c| c.empty? } + end + + def assign_nested_hash(parent, values, merge=true, metadata_hash=@attributes) + metadata_hash["#{parent}_attributes".to_sym] ||= [] + if merge + vals = metadata_hash["#{parent}_attributes".to_sym].first + vals ||= {} + vals.merge!(values) + metadata_hash["#{parent}_attributes".to_sym] = [vals] + else + metadata_hash["#{parent}_attributes".to_sym] << values + end + metadata_hash + end + + def get_person_hash(ele) + person = {} + # name + vals = get_text(ele, 'description') + person[:name] = vals[0] if vals.any? + # identifier + vals = get_text(ele, 'nims-identifier') + if vals.any? + person[:complex_identifier_attributes] = [{ + identifier: vals[0], + scheme: 'nims person id' + }] + end + # role + role = ele.name.split('-identifier', -1)[0].gsub('-', ' ') + if person.any? + term = RoleService.new.find_by_id_or_label(role) + if term.any? + person[:role] = term['id'] + else + @errors << "#{role} not in role authority" + end + end + person + end + + def get_organization_hash(ele, purpose=nil) + # TODO: Add ientifier + org = {} + vals = get_text(ele, 'organization-description/title-major-organization') + org[:organization] = vals[0] if vals.any? + vals = get_text(ele, 'organization-description/title-sub-organization') + org[:sub_organization] = vals[0] if vals.any? + org[:purpose] = purpose if org.any? and purpose.present? + org + end + + def get_identifier_hash(ele, type=nil) + id_hash = {} + ids = [] + ele.children.each do |ch| + vals = get_text(ele, ch.name) + next unless vals.any? + if ch.name == 'identifier-type' + term = IdentifierService.new.find_by_id_or_label(vals[0]) + if term.any? + id_hash[:label] = term['id'] + else + @errors << "#{vals[0]} not in identifier authority" + end + else + ids << vals[0] if vals.any? + end + end + id_hash[:identifier] = ids.uniq if ids.any? + id_hash + end + + end + end +end diff --git a/hyrax/lib/importers/dataset_importer/unpacker.rb b/hyrax/lib/importers/dataset_importer/unpacker.rb new file mode 100644 index 00000000..f6829aa6 --- /dev/null +++ b/hyrax/lib/importers/dataset_importer/unpacker.rb @@ -0,0 +1,51 @@ +require 'willow_sword' + +module Importers + module DatasetImporter + module Unpacker + + def unpack_dataset + get_metadata_file + get_dataset_files_and_title + end + + def get_metadata_file + metadata_files = Dir.glob(File.join(@import_dir, '*.xml')) + if @metadata_filename.present? + md_file = File.join(@import_dir, @metadata_filename) + @metadata_file = md_file if metadata_files.include?(md_file) + elsif metadata_files.length == 1 + @metadata_file = metadata_files[0] + end + raise StandardError, "Metadata file not found" if @metadata_file.blank? + raise StandardError, "Metadata file not found" unless File.file?(@metadata_file) + end + + def get_dataset_files_and_title + zip_files = Dir.glob(File.join(@import_dir, '*.zip')) + if zip_files.present? + @title = File.basename(zip_files[0], '.zip') + else + @title = File.basename(@import_dir) + end + zip_files.each do |zip_file| + WillowSword::ZipPackage.new(zip_file, @import_dir).unzip_file + end + all_files = Dir.glob(File.join(@import_dir, '*')) + all_files.each do |file| + # 1. List of files does not include metadata file + # 2. Directories are ignored from list of files + # 3. @files is an array of hashes, with each hash containing + # filename, filetype, filepath, metadata + next if file == @metadata_file + next if File.directory?(file) + @files << { + filename: File.basename(file), + filepath: file + } + end + end + + end + end +end diff --git a/hyrax/lib/importers/hyrax_importer.rb b/hyrax/lib/importers/hyrax_importer.rb new file mode 100644 index 00000000..2683a6b6 --- /dev/null +++ b/hyrax/lib/importers/hyrax_importer.rb @@ -0,0 +1,262 @@ +require 'fileutils' +require 'browse_everything/retriever' + +module Importers + class HyraxImporter + attr_reader :klass, :attributes, :files, :remote_files, :collections, :work_id, + :file_ids, :work_klass, :object + + def initialize(klass, attributes, files, collections, work_id=nil, depositor=nil) + @klass = klass + @attributes = attributes + @files = files + @collections = Array(collections) + @work_id = work_id ||= SecureRandom.uuid + @remote_tmp_dir = "tmp/remote_files/#{@work_id}" + set_work_klass + # Set Hyrax.config.batch_user_key + @depositor = nil + @depositor = User.find(depositor) unless depositor.blank? + @depositor = User.batch_user if @depositor.blank? + end + + def import + upload_files unless @files.blank? + add_work + if @object.save! + add_member_collections + upload_files_with_attributes unless @files.blank? + # update_work_by_actor + @object.save + end + cleanup_files + end + + def upload_files + # files is an array of hashes, with each hash containing + # filename, filetype, fileurl, filepath, metadata, uploaded_file + files.each do |file| + filepath = file.fetch(:filepath, nil) + fileurl = file.fetch(:fileurl, nil) + if fileurl.present? and filepath.blank? + filepath = upload_remote_file(file) + file[:filepath] = filepath + end + file[:uploaded_file] = upload_file(file) + end + end + + def cleanup_files + files.each do |file| + filepath = file.fetch(:filepath, nil) + fileurl = file.fetch(:fileurl, nil) + if fileurl.present? and File.exist?(filepath) + FileUtils.rm filepath + end + end + end + + def upload_file(file) + if file.fetch(:filepath, nil).blank? + message = "not uploading #{file}. No filepath fouund" + Rails.logger.warn(message) + return + end + unless File.file?(file[:filepath]) + message = "not uploading #{file}. It is not a file" + Rails.logger.warn(message) + return + end + u = ::Hyrax::UploadedFile.new + u.user = @depositor unless @depositor.nil? + u.file = ::CarrierWave::SanitizedFile.new(file[:filepath]) + u.save + u + end + + def upload_remote_file(file) + FileUtils.mkdir_p(@remote_tmp_dir) + filepath = File.join(@remote_tmp_dir, file[:filename]) + File.open(filepath, 'wb') do |f| + begin + write_file(file[:fileurl], f) + rescue StandardError => e + Rails.logger.error(e.message) + end + end + filepath + end + + def add_visibility(visibility) + # Filesets inherit visibility for work + possible_options = %w(open authenticated embargo lease restricted) + return {} unless possible_options.include? visibility + { visibility: visibility } + end + + def add_embargo(visibility_during, visibility_after, release_dt) + during_options = %w(authenticated restricted) + after_options = %w(open authenticated) + # Date should be parseable + return unless during_options.include? visibility_during + return unless after_options.include? visibility_after + { + visibility_during_embargo: visibility_during, + embargo_release_date: release_dt, + visibility_after_embargo: visibility_after + } + end + + private + + def add_work + @object = find_work if @object.blank? + if @object + update_work + else + create_work + end + end + + def find_work + # params[:id] = SecureRandom.uuid unless params[:id].present? + return find_work_by_id if @work_id + end + + def find_work_by_id + @work_klass.find(@work_id) + rescue ActiveFedora::ActiveFedoraError + nil + end + + def create_work + create_attributes[:id] = work_id + @object = @work_klass.new(create_attributes) + @object.depositor = @depositor.username + @object.admin_set_id = AdminSet.find_or_create_default_admin_set_id + end + + def update_work + raise "Object doesn't exist" unless @object + @object.update(update_attributes) + @object.depositor = @depositor.username + end + + def update_work_by_actor + raise "Object doesn't exist" unless @object + work_actor.update(environment(work_actor_attributes)) + end + + def add_member_collections + @collections.each do |collection_id| + begin + col = Collection.find(collection_id) + col.reindex_extent = Hyrax::Adapters::NestingIndexAdapter::LIMITED_REINDEX + @object.member_of_collections << col unless col.blank? + @object.save + rescue ActiveFedora::ObjectNotFoundError + puts '*** Error adding collection membership' + col = nil + end + end + end + + def create_attributes + transform_attributes + end + + def update_attributes + transform_attributes.except(:id, 'id') + end + + # @param [Hash] attrs the attributes to put in the environment + # @return [Hyrax::Actors::Environment] + def environment(attrs) + ::Hyrax::Actors::Environment.new(@object, Ability.new(@depositor), attrs) + end + + def work_actor + ::Hyrax::CurationConcern.actor + end + + # Override if we need to map the attributes from the parser in + # a way that is compatible with how the factory needs them. + def transform_attributes + # attributes.slice(*permitted_attributes).merge(file_attributes) + attributes. + except(:uploaded_files, :member_of_collections_attributes, :member_of_collection_ids, + 'uploaded_files', 'member_of_collections_attributes', 'member_of_collection_ids') + end + + def file_attributes + @file_ids.present? ? { uploaded_files: @file_ids } : {} + end + + # @example a collections attribute hash + # 'member_of_collections_attributes' => { + # '0' => { 'id' => '12312412'}, + # '1' => { 'id' => '99981228', '_destroy' => 'true' } + # } + # see: https://github.com/samvera/hyrax/blob/master/app/actors/hyrax/actors/collections_membership_actor.rb#L6 + def collection_attributes + attrs = {} + return attrs unless @collections + # @collections.each_with_index do |id, i| + # attrs["#{i}"] = { 'id' => id } + # end + # {member_of_collections_attributes: attrs} + { member_of_collection_ids: @collections } + end + + def work_actor_attributes + # {}.merge(file_attributes).merge(collection_attributes) + file_attributes + end + + def permitted_attributes + "::Hyrax::#{@klass}Form".constantize.build_permitted_params + end + + def upload_files_with_attributes + @files.each do |file| + create_file_set_with_attributes(file) + end + end + + def create_file_set_with_attributes(file_attributes) + file_set = FileSet.create + actor = ::Hyrax::Actors::FileSetActor.new(file_set, @depositor) + actor.file_set.permissions_attributes = @object.permissions.map(&:to_hash) + # Add file + actor.create_content(file_attributes[:uploaded_file]) + actor.file_set.title = Array(file_attributes[:filename]) + # update_metadata + unless file_attributes[:metadata].blank? + actor.file_set.update(file_set_attributes(file_attributes[:metadata])) + actor.file_set.save! + end + actor.attach_to_work(@object) if @object + end + + def file_set_attributes(attributes) + attributes.slice(*permitted_file_attributes).except(:id, 'id') + end + + def permitted_file_attributes + FileSet.properties.keys.map(&:to_sym) + [:id, :edit_users, :edit_groups, :read_groups, :visibility] + end + + def set_work_klass + @work_klass = @klass.constantize + end + + def write_file(uri, f, headers={}) + retriever = BrowseEverything::Retriever.new + uri_spec = { 'url' => uri }.merge(headers) + retriever.retrieve(uri_spec) do |chunk| + f.write(chunk) + end + f.rewind + end + end +end diff --git a/hyrax/lib/importers/image_importer.rb b/hyrax/lib/importers/image_importer.rb new file mode 100644 index 00000000..a579ddc0 --- /dev/null +++ b/hyrax/lib/importers/image_importer.rb @@ -0,0 +1,10 @@ +require 'importers/hyrax_importer' + +module Importers + module ImageImporter + require 'importers/image_importer/collections' + require 'importers/image_importer/profiles' + require 'importers/image_importer/parse_xml' + require 'importers/image_importer/importer' + end +end diff --git a/hyrax/lib/importers/image_importer/collections.rb b/hyrax/lib/importers/image_importer/collections.rb new file mode 100644 index 00000000..06468bad --- /dev/null +++ b/hyrax/lib/importers/image_importer/collections.rb @@ -0,0 +1,67 @@ +module Importers + module ImageImporter + module Collections + require 'importers/collection_importer' + def collections + { + 'http://imeji.nims.go.jp/imeji/collection/sdZWq3eqN1ivoU60' => { + id: '2d0752c0-fc37-4773-b764-b79ba0fc3139', + title: ['Fiber fuse damage'], + description: ['Top part of damage train left after a sudden shutdown of laser power supply.'], + related_url: ['http://imeji.nims.go.jp/imeji/collection/sdZWq3eqN1ivoU60/'], + creator: ['Shin-ichi Todoroki'], + visibility: 'open' + }, + 'http://imeji.nims.go.jp/imeji/collection/8' => { + id: '0f252c92-c493-4a69-88c1-6f869ff87d8e', + title: ['Fiber Fuse Movies'], + description: ['It looks like a tiny comet, a light-induced breakdown of a silica glass optical fiber. In situ image and fused fibers are presented. See also a YouTube video http://www.youtube.com/watch?v=BVmIgaafERk'], + related_url: ['http://imeji.nims.go.jp/imeji/collection/8'], + creator: ['Shin-ichi Todoroki'], + visibility: 'open' + }, + 'http://imeji.nims.go.jp/imeji/collection/PK_GJp0wrrycetcj' => { + id: '77e4e495-6046-4c52-9b2c-a1afb84276c1', + title: [' Fiber fuse damage 2'], + description: ['Initial part of damage train left after a fiber fuse initiation.'], + related_url: ['http://imeji.nims.go.jp/imeji/collection/PK_GJp0wrrycetcj'], + creator: ['Shin-ichi Todoroki'], + visibility: 'open' + }, + 'http://imeji.nims.go.jp/imeji/collection/DEIKQkLx77W3Jrlc' => { + id: '74e1cb36-357d-49a0-9e94-56c9213a2cf6', + title: ['フラーレンナノウィスカー'], + description: ['フラーレンナノウィスカーの成長写真'], + related_url: ['http://imeji.nims.go.jp/imeji/collection/DEIKQkLx77W3Jrlc'], + creator: ['科学情報PF (NIMS科学情報PF)'], + visibility: 'open' + }, + 'http://imeji.nims.go.jp/imeji/collection/16' => { + id: 'c8265f76-dc6a-44bd-8b63-4c87f0e3b814', + title: ['Profile information: Optical emission of Methylene Blue'], + description: ['Optical emission from Methylene Blue in ethanolic solution (excited by a green (532-nm) laser pointer).'], + related_url: ['http://imeji.nims.go.jp/imeji/collection/16'], + creator: [], + visibility: 'open' + } + } + end + + def create_collections + collections.each do |url, attributes| + unless attributes.blank? + collection = Importers::CollectionImporter.new(attributes, attributes[:id], 'open') + collection.create_collection + end + end + end + + def index_collections + collections.each do |url, attributes| + collection = Collection.find(attributes[:id]) + collection.reindex_extent = Hyrax::Adapters::NestingIndexAdapter::LIMITED_REINDEX + end + end + end + end +end diff --git a/hyrax/lib/importers/image_importer/importer.rb b/hyrax/lib/importers/image_importer/importer.rb new file mode 100644 index 00000000..08ccd7fb --- /dev/null +++ b/hyrax/lib/importers/image_importer/importer.rb @@ -0,0 +1,98 @@ +require 'nokogiri' + +module Importers + module ImageImporter + class Importer + include Importers::ImageImporter::Collections + include Importers::ImageImporter::ParseXml + attr_accessor :import_dir, :metadata_file, :debug + + def initialize(metadata_file, debug=false, log_file=nil, add_to_collection=false) + @metadata_file = metadata_file + @debug = debug + @log_file = log_file + @log_file = "data/#{Time.now.strftime('%Y-%m-%d-%H-%M-%S')}_import_imeji_log.csv" if log_file.blank? + @add_to_collection = add_to_collection + end + + def perform_create + return unless File.file?(metadata_file) + add_image_file + end + + private + # Extract metadata and return as attributes + def add_image_file + images_metadata = parse_image_file(@metadata_file) + # create_collections if @add_to_collection and not @debug + + count = 0 + images_metadata.each do |item| + # Each xml file has multiple images + count += 1 + puts '-'*80 + puts "Starting import of #{count}" + # Set defaults + work_id = nil + collection_ids = nil + attributes = {} + # files is an array of hashes, with each hash containing + # filename, filetype, fileurl, filepath, metadata + files = [] + error = '' + + # Parse metadata file + attributes = item[:metadata] + collection_url = item[:collection] + files = item[:files] + + # get collection attributes + if @add_to_collection and not @debug + collection_attrs = collections.fetch(collection_url, {}) unless collection_url.blank? + collection_ids = Array(collection_attrs.fetch(:id, nil)) + end + + # Import image + work_id = attributes[:id] unless attributes.fetch(:id, nil).blank? + unless debug + h = Importers::HyraxImporter.new('Image', attributes, files, collection_ids, work_id) + begin + h.import + rescue StandardError => exception + error = exception.backtrace.unshift(exception.message) + end + end + + # log progress + log_progress(metadata_file, work_id, collection_ids, attributes, files, error) + end + end + + def log_progress(metadata_file, work_id, collection_ids, attributes, files, error) + write_headers = true + write_headers = false if File.file?(@log_file) + csv_file = CSV.open(@log_file, "ab") + csv_file << [ + 'Current time', + 'metadata file', + 'work id', + 'collection ids', + 'attributes', + 'file attributes', + 'error' + ] if write_headers + files = '' if files.blank? + csv_file << [ + Time.now.to_s, + metadata_file, + work_id, + JSON.pretty_generate(collection_ids), + JSON.pretty_generate(attributes), + JSON.pretty_generate(files), + JSON.pretty_generate(error) + ] + csv_file.close + end + end + end +end diff --git a/hyrax/lib/importers/image_importer/parse_xml.rb b/hyrax/lib/importers/image_importer/parse_xml.rb new file mode 100644 index 00000000..cd219dff --- /dev/null +++ b/hyrax/lib/importers/image_importer/parse_xml.rb @@ -0,0 +1,394 @@ +module Importers + module ImageImporter + module ParseXml + + require 'importers/image_importer/profiles' + include Importers::ImageImporter::Profiles + + def parse_image_file(src_file) + # Open xml file with namespace + imeji_xml = Nokogiri::XML('') + doc = File.open(src_file) { |f| Nokogiri::XML(f) } + imeji_xml.root << doc.root.children + images_metadata = [] + imeji_xml.xpath('./imeji:items/imeji:item').each do |item| + images_metadata << get_image_metadata(item) + end + images_metadata + end + + def get_image_metadata(image) + return metadata if image.blank? + image_metadata = {} + image_metadata[:metadata] = get_metadata(image) + visibility = image_metadata[:metadata].fetch(:visibility, 'restricted') + # files is an array of hashes, with each hash containing + # filename, filetype, fileurl, filepath, metadata + files_info = get_files_info(image, visibility) + image_metadata[:files] = files_info[0] + default_filename = files_info[1] + image_metadata[:collection] = get_collection(image) + image_metadata = set_default_title(image_metadata, default_filename) + end + + def get_metadata(image) + metadata = {} + # id + val = get_id(image) + metadata[:id] = val unless val.blank? + # issued + val = get_issued(image) + if val.any? + metadata[:complex_date_attributes] ||= [] + metadata[:complex_date_attributes] << val + end + # visibility + val = get_visibility(image) + metadata[:visibility] = val unless val.blank? + # version + val = get_version(image) + if val.any? + metadata[:complex_version_attributes] ||= [] + metadata[:complex_version_attributes] << val + end + # metadata set + metadata = get_metadata_set(image, metadata) + # NOT interested in the following + # get_created + # get_creator + # discardComment + # escidocId + # fulltext + # modified + # modifiedBy + # status + # storageId + metadata + end + + def get_files_info(image, visibility) + # Returns an array of hashes, with each hash containing + # filename, filetype, fileurl, filepath, metadata + files = [] + default_filename = nil + # checksum - not using + filename = get_filename(image) + filetype = get_filetype(image) + full_image_url = get_full_image_url(image) + unless full_image_url.blank? + file_info = {} + this_filename = filename + this_filename = File.basename(full_image_url) if filename.blank? + default_filename = this_filename + file_info[:filename] = this_filename + file_info[:filetype] = filetype unless filetype.blank? + file_info[:fileurl] = full_image_url + metadata = {} + metadata[:title] = [this_filename] + metadata[:visibility] = 'restricted' + metadata[:resource_type] = ['Full image'] + file_info[:metadata] = metadata + files << file_info + end + web_image_url = get_web_image_url(image) + unless web_image_url.blank? + file_info = {} + this_filename = filename + this_filename = File.basename(web_image_url) if filename.blank? + default_filename = this_filename if default_filename.blank? + file_info[:filename] = this_filename + file_info[:filetype] = filetype unless filetype.blank? + file_info[:fileurl] = web_image_url + metadata = {} + metadata[:title] = [this_filename] + metadata[:visibility] = visibility + metadata[:resource_type] = ['Web image'] + file_info[:metadata] = metadata + files << file_info + end + # NOTE: Not downloading thumbnail. It is generated by Hyrax + # thumbnail_image_url = get_thumbnail_image_url(image) + # unless thumbnail_image_url.blank? + # file_info = {} + # this_filename = filename + # this_filename = File.basename(web_image_url) if filename.blank? + # default_filename = this_filename if default_filename.blank? + # file_info[:filename] = this_filename + # file_info[:filetype] = filetype unless filetype.blank? + # file_info[:fileurl] = thumbnail_image_url + # metadata = {} + # metadata[:title] = [this_filename] + # metadata[:visibility] = visibility + # metadata[:resource_type] = ['Thumbnail'] + # file_info[:metadata] = metadata + # files << file_info + # end + [files, default_filename] + end + + # ---------------------- + # descriptive metadata + # ---------------------- + def get_id(image) + pid = image.attributes.fetch('id', nil) + pid = pid.value.split('/')[-1] unless pid.blank? + pid + end + + def get_issued(image) + date_attr = {} + val = get_text(image, 'imeji:issued') + desc = DateService.new.find_by_id_or_label('Issued')['id'] + date_attr = {date: val[0], description: desc} if val.any? + date_attr + end + + def get_visibility(image) + visibility = nil + val = get_text(image, 'imeji:visibility') + if val.any? and val[0] == 'PUBLIC' + visibility = 'open' + else + visibility = 'restricted' + end + visibility + end + + def get_version(image) + version = {} + val = get_text(image, 'imeji:version') + version = {version: val[0]} if val.any? + version + end + + def get_metadata_set(image, metadata) + image.xpath('./imeji:metadataSet/imeji:metadata').each do |mds| + val = get_text(mds, './imeji:statement') + id = val.any? ? val[0] : nil + return if id.blank? + label_and_type = profiles.fetch(id, nil) + return unless label_and_type.any? + label = label_and_type[0] + type = label_and_type[1] + case type + when 'text' + vals = get_metadata_set_text(mds) + when 'number' + vals = get_metadata_set_number(mds) + when 'datetime' + vals = get_metadata_set_datetime(mds) + when 'uri' + vals = get_metadata_set_uri(mds) + when 'person' + vals = get_metadata_set_person(mds) + when 'license' + vals = get_metadata_set_license(mds) + end + if mapped_properties.include?(label) and not val.blank? + case mapped_properties[label] + when 'author' + metadata[:complex_person_attributes] ||= [] + metadata[:complex_person_attributes] << vals + when 'date' + metadata[:date_created] = [vals] + when 'description' + metadata[:description] = [vals] + when 'identifier' + metadata[:complex_identifier_attributes] ||= [] + metadata[:complex_identifier_attributes] << { identifier: vals, label: 'DOI'} + when 'instrument' + metadata[:instrument] = [vals] + when 'license' + unless vals.fetch('identifier', nil).blank? + metadata[:complex_rights_attributes] ||= [] + attrs = {} + attrs[:rights] = vals['identifier'] + attrs[:label] = vals['license'] unless vals.fetch('license', nil).blank? + metadata[:complex_rights_attributes] << attrs + end + when 'related_item' + metadata[:complex_relation_attributes] ||= [] + attrs = {} + attrs[:title] = vals['label'] unless vals.fetch('label', nil).blank? + attrs[:url] = vals['uri'] unless vals.fetch('uri', nil).blank? + attrs[:relationship] = 'isBasisFor' + metadata[:complex_relation_attributes] << attrs if attrs.any? + when 'specimen_set' + metadata[:specimen_set] = [vals] + when 'title' + metadata[:title] = [vals] + end + elsif custom_propeties.include?(label) + metadata[:custom_property_attributes] ||= [] + attrs = {} + attrs[:description] = vals + attrs[:label] = label + metadata[:custom_property_attributes] << attrs + end + end + metadata + end + + def get_metadata_set_text(node) + val = get_text(node, 'imeji:text') + val.any? ? val[0] : nil + end + + def get_metadata_set_datetime(node) + val = get_text(node, 'imeji:date') + dt = val.any? ? val[0] : nil + val = get_text(node, 'imeji:time') + tm = val.any? ? val[0] : nil + return nil if dt.blank? + return "#{dt}T00:00:00" if tm.blank? + "#{dt}T#{Time.at(tm.to_i).utc.strftime("%H:%M:%S")}" + end + + def get_metadata_set_number(node) + val = get_text(node, 'imeji:number') + val.any? ? val[0] : nil + end + + def get_metadata_set_uri(node) + data = {} + val = get_text(node, 'rdfs:label') + data['label'] = val[0] if val.any? + val = get_text(node, 'imeji:uri') + data['uri'] = val[0] if val.any? + data + end + + def get_metadata_set_license(node) + data = {} + val = get_text(node, 'dc:identifier') + data['identifier'] = val[0] if val.any? + val = get_text(node, 'imeji:license') + data['license'] = val[0] if val.any? + data + end + + def get_metadata_set_person(node) + data = {} + val = get_text(node, 'foaf:person/eterms:complete-name') + data[:name] = val[0] if val.any? + val = get_text(node, 'foaf:person/eterms:family-name') + data[:last_name] = val[0] if val.any? + val = get_text(node, 'foaf:person/eterms:given-name') + data[:first_name] = val[0] if val.any? + val = get_text(node, 'foaf:person/dc:identifier') + data[:complex_identifier_attributes] = [ + { identifier: val[0], label: 'identifier local' } + ] + id = get_text(node, 'foaf:person/eprofiles:organizationalunit/dcterms:identifier') + title = get_text(node, 'foaf:person/eprofiles:organizationalunit/dcterms:title') + if title.any? + attrs = { organization: title[0] } + if id.any? + attrs[:complex_identifier_attributes] = [ + { identifier: id[0], label: 'identifier local' } + ] + end + data[:complex_organization_attributes] = [attrs] + end + data + end + + # ------------------ + # File metadata + # ------------------ + def get_checksum(image) + val = get_text(image, 'imeji:checksum') + val.any? ? val[0] : nil + end + + def get_filename(image) + val = get_text(image, 'imeji:filename') + val.any? ? val[0] : nil + end + + def get_filetype(image) + val = get_text(image, 'imeji:filetype') + val.any? ? val[0] : nil + end + + def get_full_image_url(image) + val = get_text(image, 'imeji:fullImageUrl') + val.any? ? val[0] : nil + end + + def get_thumbnail_image_url(image) + val = get_text(image, 'imeji:thumbnailImageUrl') + val.any? ? val[0] : nil + end + + def get_web_image_url(image) + val = get_text(image, 'imeji:webImageUrl') + val.any? ? val[0] : nil + end + + # ------------------ + # collection info + # ------------------ + def get_collection(image) + val = get_text(image, 'imeji:collection') + val.any? ? val[0] : nil + end + + # ----------------- + # Default title + # ----------------- + def set_default_title(image_metadata, default_filename) + title = image_metadata.fetch(:metadata, {}).fetch(:title, nil) + if title.blank? + if default_filename.present? + image_metadata[:metadata][:title] = ["Image #{default_filename}"] + else + image_metadata[:metadata][:title] = ['Image'] + end + end + image_metadata + end + + # ------------------ + # Helper methods + # ------------------ + def get_text_with_tags(node, element) + values = [] + node.xpath("./#{element}").each do |ele| + values << ele.children.to_s + end + values.reject { |c| c.empty? } + end + + def get_text(node, element) + values = [] + node.xpath("./#{element}").each do |ele| + values << ele.text.strip if ele.text + end + values.reject { |c| c.empty? } + end + + def get_value_by_attribute(node, element) + values = {} + node.xpath("./#{element}").each do |each_ele| + each_ele.each do |attr_name, attr_value| + values[attr_name] = attr_value.strip unless attr_value.blank? + end + end + values + end + + end + end +end diff --git a/hyrax/lib/importers/image_importer/profiles.rb b/hyrax/lib/importers/image_importer/profiles.rb new file mode 100644 index 00000000..803290c5 --- /dev/null +++ b/hyrax/lib/importers/image_importer/profiles.rb @@ -0,0 +1,128 @@ +module Importers + module ImageImporter + module Profiles + + def profiles + { + "http://imeji.org/terms/statement/d79dc63-1739-47bf-8e7f-cfd0e89be517"=>["Description", 'text'], + "http://imeji.org/terms/statement/d4c198d2-4988-4cf9-8daf-c91f310fccc7"=>["Date of editing", 'datetime'], + "http://imeji.org/terms/statement/e6b94c1a-fae0-467b-9016-693c048eaf1d"=>["Date of exposure", 'datetime'], + "http://imeji.org/terms/statement/b3a5545-34e1-4fdc-88bd-d843ba48360d"=>["Camera", 'text'], + "http://imeji.org/terms/statement/c24d85ca-7229-4a02-b1f5-7149fafc9380"=>["Frame rate (fps)", 'number'], + "http://imeji.org/terms/statement/e78050d-a3ce-4489-b7c0-fe8dc6fdb92b"=>["Exposure time (s)", 'text'], + "http://imeji.org/terms/statement/af9d9a53-561a-46cb-bd2b-340f703b6c84"=>["Grayscale", 'number'], + "http://imeji.org/terms/statement/c6d800a2-9549-40e8-8b27-7b8ebd943f76"=>["Image width (pixels)", 'number'], + "http://imeji.org/terms/statement/effd334-55dd-422d-b2d6-61ca15042ee9"=>["Image height (pixels)", 'number'], + "http://imeji.org/terms/statement/a7ea9bd-8879-41a6-be32-bbaeb3e1ad57"=>["Special thanks to", 'text'], + "http://imeji.org/terms/statement/a83b2b-4633-4005-a9e2-76ab56425131"=>["Pump laser power (W)", 'number'], + "http://imeji.org/terms/statement/dab5a85-ffa0-48b3-aa17-392e7e9b06d2"=>["Pump laser wavelength (nm)", 'number'], + "http://imeji.org/terms/statement/aa6-fa80-454d-bdfb-62f4ce71c9b1"=>["Optical fiber", 'text'], + "http://imeji.org/terms/statement/bseR9OmDancAl4N"=>["Diameter (μm)", 'number'], + "http://imeji.org/terms/statement/ix7ptbU18Qn3T3S"=>["Coating", 'text'], + "http://imeji.org/terms/statement/ce6f3620-0e9e-44d0-9c92-8c33e2e68e74"=>["Sample ID", 'text'], + "http://imeji.nims.go.jp/statement/aUqgzpkZs9kdZyBg"=>["DOI", 'text'], + "http://imeji.org/terms/statement/f56d9cc-1ff8-4f7c-a114-56ba0dbd1a8d"=>["References", 'uri'], + "http://imeji.org/terms/statement/rjb2eKaIj5BeQgI0"=>["Box", 'text'], + "http://imeji.org/terms/statement/T_t6dr7qYDhFKaJa"=>["License", 'license'], + "http://imeji.org/terms/statement/yd7FyQI5t5f6DUbq"=>["Description", 'text'], + "http://imeji.org/terms/statement/hr2cqGvvpogdco5d"=>["Left-hand view", 'text'], + "http://imeji.org/terms/statement/670X2gSC8cnapC_b"=>["Right-hand view", 'text'], + "http://imeji.org/terms/statement/Xn90gppBBxoQlWnk"=>["Date of exposure", 'datetime'], + "http://imeji.org/terms/statement/T9yfGAPFcT3JXyB"=>["Camera", 'text'], + "http://imeji.org/terms/statement/m8HUg6s0QyK2gmim"=>["Pump laser power (W)", 'number'], + "http://imeji.org/terms/statement/NN11ensxqip4zP"=>["Pump laser wavelength (nm)", 'number'], + "http://imeji.org/terms/statement/05FDlO_vI9VfCbd"=>["Optical fiber", 'text'], + "http://imeji.org/terms/statement/4EWGWpQMHTFb47tH"=>["Diameter (μm)", 'number'], + "http://imeji.org/terms/statement/VGOBbUXvty_fWpJL"=>["Coating", 'text'], + "http://imeji.org/terms/statement/kHa0kVwOF9kV0mwm"=>["Propagation mode", 'text'], + "http://imeji.org/terms/statement/53FiN9xSA7WjZjAQ"=>["Periodic void interval (μm)", 'number'], + "http://imeji.org/terms/statement/C90WDA9YSnYgF4Hx"=>["Sample ID", 'text'], + "http://imeji.org/terms/statement/4T9wCy69oZjUr9"=>["References", 'uri'], + "http://imeji.org/terms/statement/hvfDwphfbqoYXgz"=>["Figure", 'number'], + "http://imeji.org/terms/statement/xfFJn0ufoFh6Qal9"=>["License", 'license'], + "http://imeji.nims.go.jp/statement/PVHZeQBnQ1TNkL5w"=>["Title", 'text'], + "http://imeji.nims.go.jp/statement/a7PLt27_99t1MvY"=>["License", 'license'], + "http://imeji.nims.go.jp/statement/oWx3iN5zaxHabFL"=>["Comment", 'text'], + "http://imeji.nims.go.jp/statement/ahtgbeVZZRg2z2kT"=>["Article_URL", 'uri'], + "http://imeji.nims.go.jp/statement/p5aUehASgFqOwK8X"=>["Item_DOI", 'uri'], + "http://imeji.nims.go.jp/statement/gDv4odKsQ_HM5cii"=>["Article_DOI", 'uri'], + "http://imeji.nims.go.jp/statement/A0w4Y4iX8yKlP95R"=>["link_to_nims_pubman", 'uri'], + "http://imeji.nims.go.jp/statement/ajCcxL579Y1GmmwV"=>["Author", 'person'], + "http://imeji.nims.go.jp/statement/3ZcWpPDJsQX9tgFI"=>["Journal", 'text'], + "http://imeji.nims.go.jp/statement/B4Gl83PMc0BzRiS1"=>["Description", 'text'], + "http://imeji.nims.go.jp/statement/Zo5jU0fOqx2rT8RV"=>["Date of exposure", 'datetime'], + "http://imeji.nims.go.jp/statement/7gzVPscDA2o4WgEI"=>["Camera", 'text'], + "http://imeji.nims.go.jp/statement/VDn7x1GtWoyxvl"=>["Pump laser power (W)", 'number'], + "http://imeji.nims.go.jp/statement/UxVdWi4ia5iOQuJE"=>["Pump laser wavelength (μm)", 'number'], + "http://imeji.nims.go.jp/statement/klwP8xv6aTr8o_0u"=>["Fusion splicer", 'text'], + "http://imeji.nims.go.jp/statement/zBQBaXV77ovqUPXv"=>["Arc discharge intensity (%)", 'number'], + "http://imeji.nims.go.jp/statement/SedhcvJzMZ2Nkvra"=>["Optical fiber", 'text'], + "http://imeji.nims.go.jp/statement/eXK5nmUsodBGpTbr"=>["Diameter (μm)", 'number'], + "http://imeji.nims.go.jp/statement/WrhQWykBRTROR8jB"=>["Coating", 'text'], + "http://imeji.nims.go.jp/statement/ykjZiIT0YYlIcuJy"=>["Sample ID", 'text'], + "http://imeji.nims.go.jp/statement/kvN4uekqe2hY3Se"=>["References", 'uri'], + "http://imeji.nims.go.jp/statement/jDbC_kst6OD_PU8s"=>["Figure",'number'], + "http://imeji.nims.go.jp/statement/6_4GsCMWUobPGCm5"=>["License", 'license'], + 'http://imeji.org/terms/statement/a8a3e41b-90c5-4a4d-9586-8cf099b94ab7'=>['Title', 'text'], + 'http://imeji.org/terms/statement/fa8b0a2-526e-427a-8461-4be32159b28e' => ['Name of substances', 'text'], + 'http://imeji.org/terms/statement/a9d30-a2b0-4a41-9099-45ac8237555f' => ['Solvent', 'text'], + 'http://imeji.org/terms/statement/e8e5-4a90-b0ef-ee3e78f609d7' => ['Wave length (nm)', 'number'], + 'http://imeji.org/terms/statement/d2088-d314-4017-9d03-fee124ba3381' => ['Light source', 'text'], + 'http://imeji.org/terms/statement/ae6f699-f0e1-45cd-b507-c88ac1aef395' => ['Temperature', 'number'], + 'http://imeji.org/terms/statement/c97edf0e-e878-4f65-94e9-0b6331ebea0b' => ['Date', 'datetime'], + 'http://imeji.org/terms/statement/d8d0dc6-7a1b-4265-b09a-bfa87902aec4' => ['References', 'uri'] + } + end + + def mapped_properties + { + 'Article_DOI' => 'related_item', + 'Article_URL' => 'related_item', + 'Author' => 'author', + 'Camera' => 'instrument', + 'Date' => 'date', + 'Description' => 'description', + 'DOI' => 'identifier', + 'Item_DOI' => 'identifier', + 'License' => 'license', + 'link_to_nims_pubman' => 'related_item', + 'References' => 'related_item', + 'Sample ID' => 'specimen_set', + 'Title' => 'title', + } + end + + def custom_propeties + [ + 'Arc discharge intensity (%)', + 'Box', + 'Coating', + 'Comment', + 'Diameter (μm)', + 'Exposure time (s)', + 'Figure', + 'Frame rate (fps)', + 'Fusion splicer', + 'Grayscale', + 'Image height (pixels)', + 'Image width (pixels)', + 'Journal', + 'Left-hand view', + 'Light source', + 'Name of substances', + 'Optical fiber', + 'Periodic void interval (μm)', + 'Propagation mode', + 'Pump laser power (W)', + 'Pump laser wavelength (nm)', + 'Pump laser wavelength (μm)', + 'Right-hand view', + 'Solvent', + 'Special thanks to', + 'Temperature', + 'Wave length (nm)' + ] + end + end + end +end diff --git a/hyrax/lib/importers/publication_importer.rb b/hyrax/lib/importers/publication_importer.rb new file mode 100644 index 00000000..30b9ba8a --- /dev/null +++ b/hyrax/lib/importers/publication_importer.rb @@ -0,0 +1,9 @@ +require 'importers/hyrax_importer' + +module Importers + module PublicationImporter + require 'importers/publication_importer/collections' + require 'importers/publication_importer/parse_xml' + require 'importers/publication_importer/importer' + end +end diff --git a/hyrax/lib/importers/publication_importer/collections.rb b/hyrax/lib/importers/publication_importer/collections.rb new file mode 100644 index 00000000..f7663df6 --- /dev/null +++ b/hyrax/lib/importers/publication_importer/collections.rb @@ -0,0 +1,39 @@ +module Importers + module PublicationImporter + module Collections + require 'importers/collection_importer' + + def collections + { + 'escidoc_dump_genso.xml' => { + title: ['Library of Strategic Natural Resources (genso)'], + id: 'genso' + }, + 'escidoc_dump_materials.xml' => { + title: ['Materials Science Library'], + id: '1544bp08d' + }, + 'escidoc_dump_nims_publications.xml' => { + title: ['NIMS Publications'], + id: 'fb4948403' + }, + 'escidoc_dump_nnin.xml' => { + title: ['NNIN collection'], + id: 'tm70mv16z' + } + } + end + + def get_collection_id + # create collection + fn = File.basename(@metadata_file) + col_attrs = collections.fetch(fn, nil) + return nil if col_attrs.blank? + col = Importers::CollectionImporter.new(col_attrs, col_attrs[:id], 'open') + collection = col.fetch_collection + return col_attrs[:id] if collection + nil + end + end + end +end diff --git a/hyrax/lib/importers/publication_importer/importer.rb b/hyrax/lib/importers/publication_importer/importer.rb new file mode 100644 index 00000000..9a649f29 --- /dev/null +++ b/hyrax/lib/importers/publication_importer/importer.rb @@ -0,0 +1,134 @@ +require 'nokogiri' + +module Importers + module PublicationImporter + class Importer + include Importers::PublicationImporter::Collections + include Importers::PublicationImporter::ParseXml + attr_accessor :import_dir, :metadata_file, :debug + + def initialize(import_dir, metadata_file, debug=false, log_file=nil, add_to_collection=false) + @import_dir = import_dir + @metadata_file = metadata_file + @debug = debug + @log_file = nil + @add_to_collection = add_to_collection + @collection = nil + @count = 0 + end + + def perform_create + return unless File.directory?(import_dir) + return unless File.file?(metadata_file) + if @add_to_collection + collection_id = get_collection_id + @collection = Array(collection_id) + end + parse_publications_file + end + + private + # Extract metadata and return as attributes + def parse_publications_file + @count += 1 + print "#{@count}." + # Each xml file has multiple items + # Each Item contains the following elements + # properties + # md-records -> md-record -> publication + # components (= files) + # relations + # resources + # Open publications xml file + work_ids = [] + pub_xml = File.open(metadata_file) { |f| Nokogiri::XML(f) } + # puts 'File read' + # Each xml file has multiple items + pub_xml.xpath('/root/item').each do |item| + # Set defaults + work_id = nil + attributes = {} + files = [] + missing_files = [] + error = nil + + # Get attributes + attributes = get_properties(item) + # puts 'got attributes' + attributes.merge!(get_metadata(item)) + # set default visibility + if attributes.any? and attributes.fetch(:visibility, nil).blank? + attributes[:visibility] = 'restricted' + end + # set dummy supervisor approval + attributes[:supervisor_approval] = ['imported from PubMan'] + # Get files + files_list = get_components(item) + files = files_list[:files] + missing_files = files_list[:missing_files] + work_id = attributes.fetch(:id, nil) + # puts work_id + # Import publication + unless debug + if work_ids.include?(work_id) + error = "Duplicate record. Not importing." + else + work_ids << work_id + h = Importers::HyraxImporter.new('Publication', attributes, files, @collection, work_id) + begin + h.import + rescue StandardError => exception + error = [] + error = [exception.message, "\n"] + Array(exception.backtrace) + puts '************ Error importing work *************' + end + # puts 'Imported work' + end + end + + # log progress + log_progress(metadata_file, work_id, @collection, files, missing_files, attributes, error) + # puts 'Added log' + end + end + + def log_progress(metadata_file, id, collection, files, missing_files, attributes, error) + log_rotate + write_headers = true + write_headers = false if File.file?(@log_file) + csv_file = CSV.open(@log_file, "ab") + csv_file << [ + 'Current time', + 'metadata file', + 'work id', + 'collection', + 'files to be added', + 'files missing', + 'attributes', + 'error' + ] if write_headers + files = '' if files.blank? + missing_files = '' if missing_files.blank? + csv_file << [ + Time.now.to_s, + metadata_file, + id, + collection, + JSON.pretty_generate(files), + JSON.pretty_generate(missing_files), + JSON.pretty_generate(attributes), + JSON.pretty_generate(error) + ] + csv_file.close + end + + def log_rotate + get_log_file if @log_file.blank? or (@count % 1000 == 0) + end + + def get_log_file + @log_file = "data/#{Time.now.strftime('%Y-%m-%d-%H-%M-%S')}_import_publication_log.csv" + end + end + end +end diff --git a/hyrax/lib/importers/publication_importer/parse_xml.rb b/hyrax/lib/importers/publication_importer/parse_xml.rb new file mode 100644 index 00000000..43f68a5f --- /dev/null +++ b/hyrax/lib/importers/publication_importer/parse_xml.rb @@ -0,0 +1,456 @@ +module Importers + module PublicationImporter + module ParseXml + + def get_properties(item) + node = item.xpath('./properties') + properties = {} + return properties if node.blank? + + # --- Parse properties --- + # The properties xml node contains the following + # pid + # creation-date + # created-by + # public-status + # public-status-comment + # version + # latest-version + # latest-release + + properties['pid'] = get_text(node, 'pid') + properties['public-status'] = get_text(node, 'public-status') + + # # could use the following properties + # properties['creation-date'] = get_text(node, 'creation-date') + # properties['created-by'] = get_value_by_attribute(node, 'created-by') + + # # Not using the following + # properties['public-status-comment'] = get_text(node, 'public-status-comment') + + # # Not sure what this is + # properties['context'] = get_value_by_attribute(node, 'context') + + # # The extracted data only has the latest version for records with multiple versions + # # We don't need to record the version number as previous version is not available + # properties['version'] = {} + # %w(number date status modified-by comment pid).each do |v_prop| + # properties['version'][v_prop] = get_text(node, "version/#{v_prop}") + # end + # properties['latest-version'] = {} + # %w(number date).each do |l_prop| + # properties['latest-version'][l_prop] = get_text(node, "latest-version/#{l_prop}") + # end + # properties['latest-release'] = {} + # %w(number date).each do |l_prop| + # properties['latest-release'][l_prop] = get_text(node, "latest-release/#{l_prop}") + # end + + # --- Map properties to publication attributes --- + attributes = {} + # Previous identifier + if properties['pid'].any? + pid = properties['pid'][0] + label = 'previous identifier' + attributes[:complex_identifier_attributes] = [{identifier: pid, label: label}] + attributes[:id] = pid.split('/')[-1].gsub('escidoc:', '').split(':')[0] + end + + # Visibility based on status + # One of two possible values - released and withdrawn + if properties['public-status'].any? + status = properties['public-status'][0] + attributes[:visibility] = 'open' if status == 'released' + attributes[:visibility] = 'restricted' if status == 'withdrawn' + end + + # could use creation-date and created-by + # Not using version properties + # ---- metadata ---- + attributes + end + + def get_metadata(publication) + node = publication.xpath('./md-records/md-record/publication') + metadata = {} + return metadata if node.blank? + # The metadata xml node contains the following + # md-records + # md-record + # publication + # abstract + # alternative + # created + # creator + # dateAccepted + # dateSubmitted + # degree + # event + # identifier + # issued + # language + # location + # modified + # published-online + # publishing-info + # review-method + # source + # subject + # tableOfContents + # title + # total-number-of-pages + metadata[:complex_date_attributes] = [] + # abstract + val = get_text(node, 'abstract') + metadata[:description] = val if val.any? + # alternative + val = get_text(node, 'alternative') + metadata[:alternative_title] = val[0] if val.any? + # created - ignoring this date for now + # creator + metadata[:complex_person_attributes] = get_creators(node) + # dateAccepted + val = get_text(node, 'dateAccepted') + desc = DateService.new.find_by_id_or_label('Accepted')['id'] + metadata[:complex_date_attributes] << {date: val, description: desc} if val.any? + # dateSubmitted + val = get_text(node, 'dateSubmitted') + desc = DateService.new.find_by_id_or_label('Submitted')['id'] + metadata[:complex_date_attributes] << {date: val, description: desc} if val.any? + # degree - not in model + # event + metadata[:complex_event_attributes] = get_event(node) + # identifier - ignoring this. we have this from properties pid + # issued + val = get_text(node, 'issued') + desc = DateService.new.find_by_id_or_label('Issued')['id'] + metadata[:complex_date_attributes] << {date: val, description: desc} if val.any? + # language + val = get_text(node, 'language') + metadata[:language] = val if val.any? + # location + val = get_text(node, 'location') + metadata[:place] = val[0] if val.any? + # modified - ignoring date modified for now + # published-online + val = get_text(node, 'published-online') + metadata[:complex_date_attributes] << {date: val[0], description: 'Published'} if val.any? + # publishing-info + # publisher + # place - Ignoring this. Not accommodated in model + val = get_text(node, 'publishing-info/publisher') + metadata[:publisher] = val if val.any? + # review-method - not in model + # source + source = get_source(node) + metadata[:complex_source_attributes] = source if source.any? + # subject + val = get_text(node, 'subject') + metadata[:subject] = val if val.any? + # tableOfContents + val = get_text(node, 'tableOfContents') + metadata[:table_of_contents] = val[0] if val.any? + # title + val = get_text(node, 'title') + metadata[:title] = val if val.any? + # total-number-of-pages + val = get_text(node, 'total-number-of-pages') + metadata[:total_number_of_pages] = val[0] if val.any? + # return + metadata + end + + def get_components(publication) + node = publication.xpath('./components/component') + files = [] + missing_files = [] + return {files: files, missing_files: missing_files} if node.blank? + # properties + properties = get_file_properties(node) + # md-records -> md-record -> file + file_metadata = get_file_metadata(node) + # gather hash of file properties + file_info = get_file_info(properties, file_metadata) + # Add filepath + pid = properties.fetch(:pid, nil) + return {files: files, missing_files: missing_files} if pid.blank? + file_id = pid.split('/')[-1].gsub('escidoc:', '').split(':')[0] + dir_path = File.join(@import_dir, file_id) + dir_list = [] + dir_list = Dir.glob("#{dir_path}/*") if File.directory?(dir_path) + if dir_list.any? + filepath = dir_list[0] + file_info[:filepath] = filepath + unless properties.fetch(:filename, nil).blank? + file_info[:filename] = File.basename(filepath) + end + if file_metadata.fetch(:title, []).blank? + file_metadata[:title] = Array(File.basename(filepath)) + end + files << file_info + else + file_info[:dirpath] = dir_path + missing_files << file_info + end + {files: files, missing_files: missing_files} + end + + def get_creators(node) + # Creator (@role) + # person + # complete-name + # family-name + # given-name + # identifier + # organization + # title + # address + # identifier + # organization + # title + # address + # identifier + creators = [] + node.xpath("./creator").each do |ele| + creator = {} + role_relator = ele.attribute('role') + creator[:role] = 'author' if role_relator == 'http://www.loc.gov/loc.terms/relators/AUT' + # complete-name + val = get_text(ele, 'person/complete-name') + creator[:name] = val if val.any? + # family-name + val = get_text(ele, 'person/family-name') + creator[:last_name] = val if val.any? + # given-name + val = get_text(ele, 'person/given-name') + creator[:first_name] = val if val.any? + # identifier - seems to be an internal escidoc identifier. So ignoring + # person - organization + # title + # ignoring address and identifier + val = get_text(ele, 'person/organization/title') + attrs = {} + if val.any? + attrs[:complex_organization_attributes] = [{ + organization: val + }] + creator[:complex_affiliation_attributes] = [attrs] + end + # Organisation -ignoring + creators << creator if creator.any? + end + creators + end + + def get_event(node) + # event + # end-date + # invitation-status + # place + # start-date + # title + events = [] + node.xpath("./event").each do |ele| + event = {} + # end-date + val = get_text(ele, 'end-date') + event[:end_date] = val if val.any? + # invitation-status + val = get_text(ele, 'invitation-status') + event[:invitation_status] = val if val.any? + # place + val = get_text(ele, 'place') + event[:place] = val if val.any? + # start-date + val = get_text(ele, 'start-date') + event[:start_date] = val if val.any? + # title + val = get_text(ele, 'title') + event[:title] = val if val.any? + events << event if event.any? + end + events + end + + def get_source(node) + # This is not modelled + # Source (@type) + # alternative + # creator + # end-page + # identifier + # issue + # publishing-info + # sequence-number + # start-page + # title + # total-number-of-pages + # volume + sources = [] + node.xpath("./source").each do |ele| + source = {} + # typ = ele.attribute('type') + # alternative title + val = get_text(ele, 'alternative') + source[:alternative_title] = val if val.any? + # creator + val = get_text(ele, 'creator') + source[:complex_person_attributes] = [{name: val, role: 'editor'}] if val.any? + # end-page + val = get_text(ele, 'end-page') + source[:end_page] = val if val.any? + # identifier + val = get_text(ele, 'identifier') + source[:complex_identifier_attributes] = [{identifier: val}] if val.any? + # issue + val = get_text(ele, 'issue') + source[:issue] = val if val.any? + # publishing-info - not in model + # sequence-number + val = get_text(ele, 'sequence-number') + source[:sequence_number] = val if val.any? + # start-page + val = get_text(ele, 'start-page') + source[:start_page] = val if val.any? + # title + val = get_text(ele, 'title') + source[:title] = val if val.any? + # total-number-of-pages + val = get_text(ele, 'total-number-of-pages') + source[:total_number_of_pages] = val if val.any? + # volume + val = get_text(ele, 'volume') + source[:volume] = val if val.any? + sources << source if source.any? + end + sources + end + + def get_file_properties(component) + node = component.xpath('./properties') + properties = {} + return properties if node.blank? + + # properties + # creation-date + # created-by @title + # valid-status + # visibility (public, audience, private) + # pid split(':')[-1] + # content-category (= resource_type) + # file-name + # mime-type + # checksum + # checksum-algorithm + val = get_text(node, 'pid') + properties[:pid] = val[0] if val.any? + unless properties[:pid] + properties[:pid] = "hdl:someHandle/test/#{component.attribute("href").value.split("/").last}" + end + vals = get_text(node, 'visibility') + val = 'restricted' + if vals.any? + if vals[0] == 'public' + val = 'open' + elsif vals[0] == 'audience' + val = 'authenticated' + else + val = 'restricted' + end + end + properties[:visibility] = val unless val.blank? + val = get_text(node, 'file-name') + properties[:filename] = val[0] if val.any? + val = get_text(node, 'mime-type') + properties[:filetype] = val[0] if val.any? + val = get_text(node, 'checksum') + properties[:checksum] = val[0] if val.any? + val = get_text(node, 'checksum-algorithm') + properties[:checksum_algorithm] = val[0] if val.any? + # # could use the following properties + # properties['creation-date'] = get_text(node, 'creation-date') + # properties['created-by'] = get_value_by_attribute(node, 'created-by') + properties + end + + def get_file_metadata(component) + # The metadata xml node contains the following + # md-records + # md-record + # file + # available + # dateCopyrighted + # description + # extent (file size) + # format + # license + # rights + # title + node = component.xpath('./md-records/md-record/file') + metadata = {} + return metadata if node.blank? + # available - not using + # val = get_text(node, 'available') + # metadata['available'] = val if val.any? + # dateCopyrighted + val = get_text(node, 'dateCopyrighted') + metadata[:date_copyrighted] = val if val.any? + # description + val = get_text(node, 'description') + metadata[:description] = val if val.any? + # extent - not using + # val = get_text(node, 'extent') + # metadata[:extent] = val if val.any? + # format - not using + # val = get_text(node, 'format') + # metadata[:format] = val if val.any? + # license + val = get_text(node, 'license') + metadata[:license] = val if val.any? + # rights_statement + val = get_text(node, 'rights') + metadata[:rights_statement] = val if val.any? + # title + val = get_text(node, 'title') + metadata[:title] = val if val.any? + metadata + end + + def get_file_info(properties, file_metadata) + file_info = {} + file_info = properties.except(:pid, :visibility) + file_metadata[:visibility] = properties.fetch(:visibility, 'restricted') + file_metadata[:resource_type] = ['Article'] + file_info[:metadata] = file_metadata + file_info + end + + def get_text_with_tags(node, element) + values = [] + node.xpath("./#{element}").each do |ele| + values << ele.children.to_s + end + values.reject { |c| c.empty? } + end + + def get_text(node, element) + values = [] + node.xpath("./#{element}").each do |ele| + values << ele.text.strip if ele.text + end + values.reject { |c| c.empty? } + end + + def get_value_by_attribute(node, element) + values = {} + node.xpath("./#{element}").each do |each_ele| + each_ele.each do |attr_name, attr_value| + values[attr_name] = attr_value.strip unless attr_value.blank? + end + end + values + end + + end + end +end diff --git a/hyrax/lib/tasks/cucumber.rake b/hyrax/lib/tasks/cucumber.rake new file mode 100644 index 00000000..d6113517 --- /dev/null +++ b/hyrax/lib/tasks/cucumber.rake @@ -0,0 +1,76 @@ +# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. +# It is recommended to regenerate this file in the future when you upgrade to a +# newer version of cucumber-rails. Consider adding your own code to a new file +# instead of editing this one. Cucumber will automatically load all features/**/*.rb +# files. + + +unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks + +vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? + +begin + require 'cucumber/rake/task' + + namespace :cucumber do + Cucumber::Rake::Task.new({ok: 'test:prepare'}, 'Run features that should pass') do |t| + t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. + t.fork = true # You may get faster startup if you set this to false + t.profile = 'default' + end + + Cucumber::Rake::Task.new({wip: 'test:prepare'}, 'Run features that are being worked on') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'wip' + end + + Cucumber::Rake::Task.new({rerun: 'test:prepare'}, 'Record failing features and run only them if any exist') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'rerun' + end + + desc 'Run all features' + task all: [:ok, :wip] + + task :statsetup do + require 'rails/code_statistics' + ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features') + ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features') + end + + task :annotations_setup do + Rails.application.configure do + if config.respond_to?(:annotations) + config.annotations.directories << 'features' + config.annotations.register_extensions('feature') { |tag| /#\s*(#{tag}):?\s*(.*)$/ } + end + end + end + end + desc 'Alias for cucumber:ok' + task cucumber: 'cucumber:ok' + + task default: :cucumber + + task features: :cucumber do + STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" + end + + # In case we don't have the generic Rails test:prepare hook, append a no-op task that we can depend upon. + task 'test:prepare' do + end + + task stats: 'cucumber:statsetup' + + task notes: 'cucumber:annotations_setup' +rescue LoadError + desc 'cucumber rake task not available (cucumber not installed)' + task :cucumber do + abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' + end +end + +end diff --git a/hyrax/lib/tasks/db_exists.rake b/hyrax/lib/tasks/db_exists.rake new file mode 100644 index 00000000..4103f4ab --- /dev/null +++ b/hyrax/lib/tasks/db_exists.rake @@ -0,0 +1,13 @@ +namespace :db do + desc "Checks to see if the database exists" + task :exists do + begin + Rake::Task['environment'].invoke + ActiveRecord::Base.connection + rescue + exit 1 + else + exit 0 + end + end +end diff --git a/hyrax/lib/tasks/setup_hyrax.rake b/hyrax/lib/tasks/setup_hyrax.rake new file mode 100644 index 00000000..18d6d4d4 --- /dev/null +++ b/hyrax/lib/tasks/setup_hyrax.rake @@ -0,0 +1,54 @@ +namespace :ngdr do + desc 'Setup Hyrax, will read from specified file usage: ngdr:setup_hyrax["setup.json"]' + task :"setup_hyrax", [:seedfile] => :environment do |task, args| + seedfile = args.seedfile + unless args.seedfile.present? + seedfile = Rails.root.join("seed","setup.json") + end + + if (File.exists?(seedfile)) + puts("Running hyrax setup from seedfile: #{seedfile}") + else + abort("ERROR: missing seedfile for hyrax setup: #{seedfile}") + end + + seed = JSON.parse(File.read(seedfile)) + + ############################################## + # make the requested users + ###### + + depositor = false + admin = Role.where(name: "admin").first_or_create! + seed["users"].each do |user| + newUser = User.where(username: user["username"]).first_or_create!(password: user["password"], display_name: user["name"], email: user["email"]) + + if user["role"] == "admin" + unless admin.users.include?(newUser) + admin.users << newUser + admin.save! + end + end + + if user.has_key?("depositor") + depositor = newUser + end + end + + # finished creating users + ############################################## + + + ############################################## + # Create default administrative set + ###### + Rake::Task['hyrax:default_admin_set:create'].invoke + Rake::Task['hyrax:workflow:load'].invoke + Rake::Task['hyrax:default_collection_types:create'].invoke + + ############################################## + # Create languages controlled vocabulary + ###### + Rake::Task['hyrax:controlled_vocabularies:language'].invoke if Qa::Authorities::Local.subauthority_for('languages').all.size == 0 + end +end diff --git a/hyrax/lib/tasks/test_servers.rake b/hyrax/lib/tasks/test_servers.rake new file mode 100644 index 00000000..cf44f3a1 --- /dev/null +++ b/hyrax/lib/tasks/test_servers.rake @@ -0,0 +1,60 @@ +FEDORA_PID_FILE = 'tmp/.fedora-test.pid' +SOLR_PID_FILE = 'tmp/.solr-test.pid' +MINTER_FILE = 'tmp/minter' + +namespace :test do + namespace :servers do + + desc "Load the solr options and solr instance" + task :environment do + abort "ERROR: must be run with RAILS_ENV=test (currently: #{ENV['RAILS_ENV']})" unless ENV['RAILS_ENV'] == 'test' + + SolrWrapper.default_instance_options = { config: 'config/solr_wrapper_test.yml' } + @solr_instance = SolrWrapper.default_instance + @fcrepo_instance = FcrepoWrapper.default_instance(config: 'config/fcrepo_wrapper_test.yml') + end + + desc 'Starts a test Solr and Fedora instance for running cucumber tests' + task :start => :environment do + abort "WARNING: Solr-test is already running; run \"rake test:servers:stop\" to stop it" if File.exists?(SOLR_PID_FILE) + abort "WARNING: Fedora-test is already running; run \"rake test:servers:stop\" to stop it" if File.exists?(FEDORA_PID_FILE) + + # clean out any old solr files + @solr_instance.remove_instance_dir! + @solr_instance.extract_and_configure + + # start solr + @solr_instance.start + # create the core - a bit of a bodge is required to get the correct collection options + collection_options = HashWithIndifferentAccess.new(@solr_instance.config.options[:collection].except(:name)) + @solr_instance.create(collection_options) + File.write(SOLR_PID_FILE, @solr_instance.pid) + + # start fedora + @fcrepo_instance.remove_instance_dir! + @fcrepo_instance.start + File.write(FEDORA_PID_FILE, @fcrepo_instance.pid) + end + + task :stop => :environment do + # kill fedora and clean up + if File.exists?(FEDORA_PID_FILE) + # NB: we cannot use @fcrepo_instance.stop here as the @instance does not know its PID, so kill in the conventional way instead + Process.kill 'HUP', File.read(FEDORA_PID_FILE).to_i + File.delete(FEDORA_PID_FILE) + sleep(0.5) + @fcrepo_instance.remove_instance_dir! + end + + # stop solr and clean up + if File.exists?(SOLR_PID_FILE) + @solr_instance.stop + File.delete(SOLR_PID_FILE) + @solr_instance.remove_instance_dir! + end + + # delete the test minter file + File.delete(MINTER_FILE) if File.exists?(MINTER_FILE) + end + end +end diff --git a/hyrax/lib/tasks/wikibase.rake b/hyrax/lib/tasks/wikibase.rake new file mode 100644 index 00000000..953a7cd7 --- /dev/null +++ b/hyrax/lib/tasks/wikibase.rake @@ -0,0 +1,39 @@ +require 'csv' + +namespace :wikibase do + desc 'Fetch Wikibase TSV' + task :fetch_synonym, ['filename'] => :environment do |task, args| + Rails.logger.formatter = ::Logger::Formatter.new + Rails.logger.info("Started Wikibase import task") + + url = ENV.fetch('WIKIBASE_BASE_URL') + filename = args['filename'] + raise 'Please specify filename.' unless filename + + conn = Faraday.new(url: url) do |req| + req.use FaradayMiddleware::FollowRedirects + req.headers['Accept'] = 'application/sparql-results+json' + req.adapter :net_http + end + + res = conn.get ENV.fetch('WIKIBASE_SPARQL_QUERY_SYNONYM') + + json = JSON.parse(res.body.force_encoding('UTF-8')) + File.open(filename, 'wb'){|file| + json['results']['bindings'].each do |row| + file.write row['synonyms']['value'].split("\t").to_csv + end + } + + Rails.logger.info("Completed Wikibase import task") + end + + task :reload_solr_core do |task| + response = Net::HTTP.get_response(URI("http://#{ENV.fetch('SOLR_HOST')}:#{ENV.fetch('SOLR_PORT')}/solr/admin/cores?action=RELOAD&core=#{ENV.fetch('SOLR_CORE')}")) + if response.message == 'OK' + puts response.message + else + raise 'Failed to reload Solr core' + end + end +end diff --git a/hyrax/lib/vocabularies/escidoc_publication.rb b/hyrax/lib/vocabularies/escidoc_publication.rb new file mode 100644 index 00000000..7e8a8e61 --- /dev/null +++ b/hyrax/lib/vocabularies/escidoc_publication.rb @@ -0,0 +1,18 @@ +module RDF + module Vocab + class ESciDocPublication < RDF::Vocabulary("http://purl.org/escidoc/metadata/terms/0.1/") + property :Event + property :Source + property :creator + property 'end-page' + property :event + property :issue + property :place + property 'sequence-number' + property 'start-page' + property 'total-number-of-pages' + property :source + property :volume + end + end +end diff --git a/hyrax/lib/vocabularies/nims_rdp.rb b/hyrax/lib/vocabularies/nims_rdp.rb new file mode 100644 index 00000000..7ab568e8 --- /dev/null +++ b/hyrax/lib/vocabularies/nims_rdp.rb @@ -0,0 +1,60 @@ +module RDF + module Vocab + class NimsRdp < RDF::Vocabulary("http://www.nims.go.jp/vocabs/ngdr/") + property 'CustomProperty' + property 'ChemicalComposition' + property 'CrystallographicStructure' + property 'History' + property 'Instrument' + property 'InstrumentFunction' + property 'MaterialType' + property 'PurchaseRecord' + property 'Shape' + property 'Specimen' + property 'StateOfMatter' + property 'downstream' + property 'category' + property 'characterization-methods' + property 'chemical-composition' + property 'computational-methods' + property 'crystallographic-structure' + property 'custom-property' + property 'data-origin' + property 'history' + property 'identifier' + property 'instrument' + property 'instrument-date' + property 'instrument-function' + property 'instrument-manufacturer' + property 'instrument-model-number' + property 'instrument-operator' + property 'instrument-organization' + property 'instrument-title' + property 'material-type' + property 'sub-category' + property 'material-sub-type' + property 'origin-system-provenance' + property 'properties-addressed' + property 'purchase-date' + property 'purchase-record' + property 'purchase-record-date' + property 'purchase-record-identifier' + property 'purchase-record-item' + property 'purchase-record-title' + property 'upstream' + property 'shape' + property 'specimen-set' + property 'specimen-title' + property 'specimen-type' + property 'state-of-matter' + property 'structural-feature' + property 'sub-category' + property 'supplier' + + property 'synthesis-and-processing' + property 'version' + property 'version-date' + property 'version-identifier' + end + end +end diff --git a/hyrax/lib/vocabularies/rioxx_terms.rb b/hyrax/lib/vocabularies/rioxx_terms.rb new file mode 100644 index 00000000..05ee28dd --- /dev/null +++ b/hyrax/lib/vocabularies/rioxx_terms.rb @@ -0,0 +1,16 @@ +module RDF + module Vocab + class RioxxTerms < RDF::Vocabulary("http://data2paper.org/vocabularies/rioxxterms#") + property :apc + property :author + property :contributor + property :funder_id + property :funder_name + property :project + property :publication_date + property :type + property :version + property :version_of_record + end + end +end diff --git a/hyrax/package.json b/hyrax/package.json new file mode 100644 index 00000000..9ae7710d --- /dev/null +++ b/hyrax/package.json @@ -0,0 +1,17 @@ +{ + "name": "nims-hyrax", + "private": true, + "repository": "git@github.com:antleaf/nims-hyrax.git", + "dependencies": { + "universalviewer": "3.0.16" +}, +"scripts": { + "preinstall": "rm -rf ./public/uv", + "postinstall": "yarn run uv-install && yarn run uv-config", + "uv-install": "shx cp -r ./node_modules/universalviewer/uv ./public/", + "uv-config": "shx cp ./config/uv/uv.html ./public/uv/uv.html & shx cp ./config/uv/uv-config.json ./public/uv/" + }, + "devDependencies": { + "shx": "^0.3.2" + } +} diff --git a/hyrax/public/apple-touch-icon-precomposed.png b/hyrax/public/apple-touch-icon-precomposed.png index e69de29b..cf6370f9 100644 Binary files a/hyrax/public/apple-touch-icon-precomposed.png and b/hyrax/public/apple-touch-icon-precomposed.png differ diff --git a/hyrax/public/apple-touch-icon.png b/hyrax/public/apple-touch-icon.png index e69de29b..7fbeebec 100644 Binary files a/hyrax/public/apple-touch-icon.png and b/hyrax/public/apple-touch-icon.png differ diff --git a/hyrax/public/favicon.ico b/hyrax/public/favicon.ico index e69de29b..c79dc34d 100644 Binary files a/hyrax/public/favicon.ico and b/hyrax/public/favicon.ico differ diff --git a/hyrax/script/cucumber b/hyrax/script/cucumber new file mode 100755 index 00000000..eb5e962e --- /dev/null +++ b/hyrax/script/cucumber @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first +if vendored_cucumber_bin + load File.expand_path(vendored_cucumber_bin) +else + require 'rubygems' unless ENV['NO_RUBYGEMS'] + require 'cucumber' + load Cucumber::BINARY +end diff --git a/hyrax/seed/.keep b/hyrax/seed/.keep new file mode 100644 index 00000000..e69de29b diff --git a/hyrax/seed/setup.json b/hyrax/seed/setup.json new file mode 100644 index 00000000..e8ddfc25 --- /dev/null +++ b/hyrax/seed/setup.json @@ -0,0 +1,28 @@ +{ + "users": [{ + "email": "admin@hyrax", + "username": "admin_hyrax", + "password": "password", + "name": "hyrax Admin", + "role": "admin", + "user_identifier": "urn:USER_IDENTIFIER.dpfc.nims.go.jp:8c5f864c-c315-49c0-a49d-609895a8925d" + }, + { + "email": "user@hyrax", + "username": "user_hyrax", + "password": "demouser", + "name": "Demo User", + "role": "user", + "depositor": true, + "user_identifier": "urn:USER_IDENTIFIER.dpfc.nims.go.jp:ebb7db80-27ef-4d3c-896d-e5956ee22ca5" + }, + { + "email": "workflow@hyrax", + "username": "workflow_hyrax", + "password": "workflow", + "name": "Workflow Admin", + "role": "admin", + "user_identifier": "urn:USER_IDENTIFIER.dpfc.nims.go.jp:5a882edb-377f-4f35-85b1-a0963293c261" + } + ] +} diff --git a/hyrax/shared/log/.keep b/hyrax/shared/log/.keep new file mode 100644 index 00000000..2e9fdd62 --- /dev/null +++ b/hyrax/shared/log/.keep @@ -0,0 +1 @@ +# Required for puma hyrax/config/puma.rb \ No newline at end of file diff --git a/hyrax/shared/log/puma.stderr.log b/hyrax/shared/log/puma.stderr.log deleted file mode 100644 index b79d2f54..00000000 --- a/hyrax/shared/log/puma.stderr.log +++ /dev/null @@ -1,114 +0,0 @@ -=== puma startup: 2018-05-01 06:43:15 +0000 === -=== puma startup: 2018-05-01 06:46:32 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/binder.rb:65:in `for_fd': Bad file descriptor - not a socket file descriptor (Errno::EBADF) - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/binder.rb:65:in `block (2 levels) in import_from_env' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/binder.rb:63:in `times' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/binder.rb:63:in `block in import_from_env' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/binder.rb:57:in `each' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/binder.rb:57:in `import_from_env' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/launcher.rb:52:in `initialize' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/cli.rb:69:in `new' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/lib/puma/cli.rb:69:in `initialize' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/bin/puma:8:in `new' - from /home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/puma-3.11.4/bin/puma:8:in `' - from /home/appuser/.rbenv/versions/2.4.2/bin/puma:23:in `load' - from /home/appuser/.rbenv/versions/2.4.2/bin/puma:23:in `
    ' -=== puma startup: 2018-05-01 06:55:44 +0000 === -=== puma startup: 2018-05-01 06:57:33 +0000 === -=== puma startup: 2018-05-01 07:00:02 +0000 === -=== puma startup: 2018-05-01 07:00:31 +0000 === -=== puma startup: 2018-05-01 07:03:18 +0000 === -=== puma startup: 2018-07-02 20:17:06 +0000 === -=== puma startup: 2018-07-02 21:46:06 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-07-03 00:27:34 +0000 === -=== puma startup: 2018-07-03 00:30:39 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-07-03 02:35:58 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-07-03 03:41:29 +0000 === -=== puma startup: 2018-07-03 03:44:34 +0000 === -=== puma startup: 2018-07-03 03:46:22 +0000 === -=== puma startup: 2018-07-03 03:59:17 +0000 === -=== puma startup: 2018-07-03 04:07:53 +0000 === -=== puma startup: 2018-07-03 04:10:50 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-07-03 05:10:32 +0000 === -=== puma startup: 2018-07-03 05:11:02 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-07-03 10:34:34 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-07-03 11:02:02 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0.rc1/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-07-06 09:43:45 +0000 === -=== puma startup: 2018-07-06 09:44:35 +0000 === -=== puma startup: 2018-07-06 09:48:40 +0000 === -=== puma startup: 2018-07-09 11:24:27 +0000 === -=== puma startup: 2018-07-13 11:37:10 +0000 === -=== puma startup: 2018-07-13 11:54:20 +0000 === -=== puma startup: 2018-07-16 23:11:58 +0000 === -=== puma startup: 2018-07-16 23:21:12 +0000 === -=== puma startup: 2018-07-16 23:30:33 +0000 === -=== puma startup: 2018-07-16 23:35:46 +0000 === -=== puma startup: 2018-07-17 01:43:19 +0000 === -=== puma startup: 2018-07-17 01:45:05 +0000 === -=== puma startup: 2018-07-17 02:00:31 +0000 === -=== puma startup: 2018-07-17 02:15:12 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-07-18 22:58:53 +0000 === -=== puma startup: 2018-07-18 23:24:10 +0000 === -=== puma startup: 2018-07-18 23:26:39 +0000 === -=== puma startup: 2018-07-18 23:30:11 +0000 === -=== puma startup: 2018-07-18 23:34:21 +0000 === -=== puma startup: 2018-07-18 23:37:28 +0000 === -=== puma startup: 2018-07-18 23:57:15 +0000 === -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -/home/appuser/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/hyrax-2.1.0/app/views/hyrax/file_sets/media_display/_pdf.html.erb:10: warning: key :data is duplicated and overwritten on line 13 -=== puma startup: 2018-11-05 12:30:53 +0000 === -=== puma startup: 2018-11-05 12:40:50 +0000 === diff --git a/hyrax/shared/log/puma.stdout.log b/hyrax/shared/log/puma.stdout.log deleted file mode 100644 index a4fe7b93..00000000 --- a/hyrax/shared/log/puma.stdout.log +++ /dev/null @@ -1,1543 +0,0 @@ -=== puma startup: 2018-05-01 06:43:15 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-05-01 06:43:31 +0000 === -- Goodbye! -=== puma startup: 2018-05-01 06:46:32 +0000 === -* Restarting... -=== puma startup: 2018-05-01 06:55:44 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-05-01 06:57:23 +0000 === -- Goodbye! -=== puma startup: 2018-05-01 06:57:33 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-05-01 06:59:05 +0000 === -- Goodbye! -=== puma startup: 2018-05-01 07:00:02 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-05-01 07:00:15 +0000 === -- Goodbye! -=== puma startup: 2018-05-01 07:00:31 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-05-01 07:02:53 +0000 === -- Goodbye! -=== puma startup: 2018-05-01 07:03:18 +0000 === -=== puma startup: 2018-07-02 20:17:06 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-02 20:31:41 +0000 === -- Goodbye! -=== puma startup: 2018-07-02 21:46:06 +0000 === -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/dce8b265-4f3f-490e-b66a-0a435988a3ab/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["CC-0"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/dce8b265-4f3f-490e-b66a-0a435988a3ab/bag/data/images/data2paper.png -tmp/data/dce8b265-4f3f-490e-b66a-0a435988a3ab/bag/data/Swordv2Spec.pdf -tmp/data/dce8b265-4f3f-490e-b66a-0a435988a3ab/bag/data/bagitSpec.pdf --------------------------------------------------- -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/362bfad7-b3ad-4407-a3e2-cf7c57e3c791/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["CC-0"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/362bfad7-b3ad-4407-a3e2-cf7c57e3c791/bag/data/images/data2paper.png -tmp/data/362bfad7-b3ad-4407-a3e2-cf7c57e3c791/bag/data/Swordv2Spec.pdf -tmp/data/362bfad7-b3ad-4407-a3e2-cf7c57e3c791/bag/data/bagitSpec.pdf --------------------------------------------------- -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/0acb78e2-e713-4a5b-bf2b-78636ffe20b0/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["CC-0"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/0acb78e2-e713-4a5b-bf2b-78636ffe20b0/bag/data/images/data2paper.png -tmp/data/0acb78e2-e713-4a5b-bf2b-78636ffe20b0/bag/data/Swordv2Spec.pdf -tmp/data/0acb78e2-e713-4a5b-bf2b-78636ffe20b0/bag/data/bagitSpec.pdf --------------------------------------------------- -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/41906ead-d418-4b0d-82c1-b54563ebf29a/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["CC-0"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/41906ead-d418-4b0d-82c1-b54563ebf29a/bag/data/images/data2paper.png -tmp/data/41906ead-d418-4b0d-82c1-b54563ebf29a/bag/data/Swordv2Spec.pdf -tmp/data/41906ead-d418-4b0d-82c1-b54563ebf29a/bag/data/bagitSpec.pdf --------------------------------------------------- -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/63a178c8-ef59-46e7-8e4e-56249453b362/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["CC-0"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/63a178c8-ef59-46e7-8e4e-56249453b362/bag/data/images/data2paper.png -tmp/data/63a178c8-ef59-46e7-8e4e-56249453b362/bag/data/Swordv2Spec.pdf -tmp/data/63a178c8-ef59-46e7-8e4e-56249453b362/bag/data/bagitSpec.pdf --------------------------------------------------- -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/480a7243-40c6-42bf-9b67-3a137cfa343d/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["CC-0"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/480a7243-40c6-42bf-9b67-3a137cfa343d/bag/data/images/data2paper.png -tmp/data/480a7243-40c6-42bf-9b67-3a137cfa343d/bag/data/Swordv2Spec.pdf -tmp/data/480a7243-40c6-42bf-9b67-3a137cfa343d/bag/data/bagitSpec.pdf --------------------------------------------------- -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/3ff957e0-ffa2-4599-a83f-e0fd530d9f7d/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["CC-0"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/3ff957e0-ffa2-4599-a83f-e0fd530d9f7d/bag/data/images/data2paper.png -tmp/data/3ff957e0-ffa2-4599-a83f-e0fd530d9f7d/bag/data/Swordv2Spec.pdf -tmp/data/3ff957e0-ffa2-4599-a83f-e0fd530d9f7d/bag/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [7, 8, 9] -In add_work -In find -In find_by_id -In create_work -In create_attributes -Content type: application/zip -Filename: testPackageInBagit.zip -MD5 hash: c058e3a3eba263df481ebf69ba2305f7 -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -324668 -File path: tmp/data/ed0e6607-c1c0-47a4-b9eb-9aaf1bcab528/testPackageInBagit.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha Ranganathan", "Another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["CC-0"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 1"]} --------------------------------------------------- -tmp/data/ed0e6607-c1c0-47a4-b9eb-9aaf1bcab528/contents/data/Swordv2Spec.pdf -tmp/data/ed0e6607-c1c0-47a4-b9eb-9aaf1bcab528/contents/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [10, 11] -In add_work -In find -In find_by_id -In create_work -In create_attributes -Content type: application/zip -Filename: testPackageInBagit.zip -MD5 hash: c058e3a3eba263df481ebf69ba2305f7 -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/bc018b12-6d8e-493a-8d7c-6a7460f56628/testPackageInBagit.zip -File exists: true -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/d167771a-e112-4b23-b8a5-b0ed5a9b5ea3/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["Copyright Not Evaluated"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/d167771a-e112-4b23-b8a5-b0ed5a9b5ea3/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [12] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/56948c35-5554-4a68-891b-8c49818863ea -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/28f87d0a-0e86-49fb-a764-e03f61c62e29/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["Copyright Not Evaluated"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/28f87d0a-0e86-49fb-a764-e03f61c62e29/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [13] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/314171ae-ac48-4ff0-ab4b-d49d150e731d -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/31403fb7-0236-4bce-ae08-1056928e033b/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :relation=>["http://example.com"], :rights=>["Copyright Not Evaluated"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/31403fb7-0236-4bce-ae08-1056928e033b/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [14] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/ea71cee7-9d01-45d9-97e5-8d427594bea9 -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 00:26:51 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 00:27:34 +0000 === -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/58badf02-786a-402f-ac27-b44b1ee4ab61/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/1bb7c51f-421e-40b5-9385-e69fe9abccdf/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 00:29:26 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 00:30:39 +0000 === -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/0d7d103b-5eca-4593-b805-41bcc0482cdc/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/0d7d103b-5eca-4593-b805-41bcc0482cdc/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [15] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/2a65a9d6-d9c9-4cc8-b9f1-880c4efa0519 -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/3523be52-ec92-4a5a-9880-6fbc6180f789/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/3523be52-ec92-4a5a-9880-6fbc6180f789/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [16] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/c0698357-11ee-43d5-bb9e-bfb2eea50d8c -Content type: application/atom+xml;type=entry -Filename: metadara.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -17 -File path: tmp/data/3ecb0f06-a30d-4232-8c36-d165d6372183/metadara.xml -File exists: true -Mime type: text/plain -Unknown format of data -In add_work -In find -Content type: application/atom+xml;type=entry -Filename: metadara.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1145 -File path: tmp/data/2dbf071e-02b8-45fa-a004-81e4a69a5adf/metadara.xml -File exists: true -Mime type: application/xml -process xml -{:title=>["Title"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/204aa903-8d7a-4042-8122-eb3aa43111c3 -Content type: application/atom+xml;type=entry -Filename: metadara.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1145 -File path: tmp/data/6fa71909-75ca-43e7-84db-97c30c30104f/metadara.xml -File exists: true -Mime type: application/xml -process xml -{:title=>["Title"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/38f67c08-afdc-4994-aed6-02d84a9795dd -Content type: application/atom+xml;type=entry -Filename: metadata.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1145 -File path: tmp/data/e31b9e97-d2e3-434a-ac83-7bb1bc7eacb1/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:title=>["Title"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/24175f4d-cd55-4566-9874-c01b38a28011 -Content type: application/atom+xml;type=entry -Filename: metadata.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1145 -File path: tmp/data/970b1b00-5f1d-4c36-a11c-1e226dd58e32/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:title=>["Title"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/b48c0612-52de-49f4-a17a-22a30fbf999c -Content type: application/atom+xml;type=entry -Filename: metadata.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1145 -File path: tmp/data/1c2285d6-0b02-4d2a-983e-c0eb0625f474/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:title=>["Title"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/2a6346c3-284f-44de-ac96-898bb43de5c0 -Content type: application/atom+xml;type=entry -Filename: metadata.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -970 -File path: tmp/data/24ba95db-4736-4763-8790-ced891ddc245/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["The dublin core generator"], :date_created=>["29/05/2018"], :creator=>["Anusha"], :description=>["This is a test dc record to test the dc crosswalk and creation of a metadata only record"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record with only metadata"], :resource_type=>["Article"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/060d40c5-65b0-458d-ad71-b422bbd4500c -Content type: application/atom+xml;type=entry -Filename: metadata.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1182 -File path: tmp/data/30ad1dbd-07e9-4cda-bc64-8595560eb19d/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["The dublin core generator"], :date_created=>["29/05/2018"], :creator=>["Anusha"], :description=>["This is a test dc record to test the dc crosswalk and creation of a metadata only record"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Title", "Test record with only metadata"], :resource_type=>["Article"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/ee7c3074-df19-4862-99f0-f7d7c390005b -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/a6c12338-94a5-4eeb-9101-5640dcb9b75c/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"CC-0", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/a6c12338-94a5-4eeb-9101-5640dcb9b75c/bag/data/images/data2paper.png -tmp/data/a6c12338-94a5-4eeb-9101-5640dcb9b75c/bag/data/Swordv2Spec.pdf -tmp/data/a6c12338-94a5-4eeb-9101-5640dcb9b75c/bag/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [17, 18, 19] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/12f3af39-4715-42fe-9792-e64c69ad2ab6 -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 02:35:52 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 02:35:58 +0000 === -In find -In find -In find -In find_by_id -In find -In find_by_id -In find -In find_by_id -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/def94b1e-e86c-4713-b40f-cfd64e55046a/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :date_created=>["29/05/2018"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/def94b1e-e86c-4713-b40f-cfd64e55046a/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [20] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/9w032300g -In find -In find_by_id -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 03:41:23 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 03:41:29 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 03:44:28 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 03:44:34 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 03:45:04 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 03:46:22 +0000 === -In find -In find_by_id -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 03:58:31 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 03:59:17 +0000 === -In find -In find_by_id -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 04:03:47 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 04:07:53 +0000 === -In find -In find_by_id -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 04:10:26 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 04:10:50 +0000 === -In find -In find_by_id -In find -In find_by_id -In find -In find_by_id -In find -In find_by_id -In find -In find_by_id -In find -In find_by_id -Content type: application/atom+xml;type=entry -Filename: metadata.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1182 -File path: tmp/data/d3ab2a3e-ba13-4479-a340-ea5be99c896c/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["The dublin core generator"], :date_created=>["29/05/2018"], :creator=>["Anusha"], :description=>["This is a test dc record to test the dc crosswalk and creation of a metadata only record"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Title", "Test record with only metadata"], :resource_type=>["Article"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/qz20ss48r -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/e9cb794c-a972-4983-b859-00f252d465e6/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :date_created=>["29/05/2018"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/e9cb794c-a972-4983-b859-00f252d465e6/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [21] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/k930bx00t -Content type: application/zip -Filename: testPackage1InBagit.zip -MD5 hash: c058e3a3eba263df481ebf69ba2305f7 -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -324668 -File path: tmp/data/bdb338a2-bec9-4e25-ac6a-2b01a678513d/testPackage1InBagit.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha Ranganathan", "Another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"CC-0", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 1"]} --------------------------------------------------- -tmp/data/bdb338a2-bec9-4e25-ac6a-2b01a678513d/contents/data/Swordv2Spec.pdf -tmp/data/bdb338a2-bec9-4e25-ac6a-2b01a678513d/contents/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [22, 23] -In add_work -In find -In find_by_id -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/bn999672v -In find -In find_by_id -In find -In find_by_id -In find -In find_by_id -In find -In find_by_id -In find -In find_by_id -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 05:10:25 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 05:10:32 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 05:10:37 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 05:11:02 +0000 === -In find -In find_by_id -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 10:29:42 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 10:34:34 +0000 === -In find_work -In find_work_by_id -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-03 11:01:55 +0000 === -- Goodbye! -=== puma startup: 2018-07-03 11:02:02 +0000 === -Content type: application/zip -Filename: metadata.xml -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1182 -File path: tmp/data/35b30db1-e776-4a14-ac4b-7fddc64b15b5/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["The dublin core generator"], :date_created=>["29/05/2018"], :creator=>["Anusha"], :description=>["This is a test dc record to test the dc crosswalk and creation of a metadata only record"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Title", "Test record with only metadata"], :resource_type=>["Article"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/6395w7085 -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/68a07bdc-e25f-4f4e-9347-fc27ab86acf5/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :date_created=>["29/05/2018"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/68a07bdc-e25f-4f4e-9347-fc27ab86acf5/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [24] -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/dn39x152w -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/4ef89a56-4e6e-483a-b7e9-991bde8a52e6/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"CC-0", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/4ef89a56-4e6e-483a-b7e9-991bde8a52e6/bag/data/images/data2paper.png -tmp/data/4ef89a56-4e6e-483a-b7e9-991bde8a52e6/bag/data/Swordv2Spec.pdf -tmp/data/4ef89a56-4e6e-483a-b7e9-991bde8a52e6/bag/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [25, 26, 27] -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/8g84mm241 -Content type: application/zip -Filename: testPackage1InBagit.zip -MD5 hash: c058e3a3eba263df481ebf69ba2305f7 -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -324668 -File path: tmp/data/c7782601-8634-4386-8e33-18b6f9790b33/testPackage1InBagit.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha Ranganathan", "Another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"CC-0", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 1"]} --------------------------------------------------- -tmp/data/c7782601-8634-4386-8e33-18b6f9790b33/contents/data/Swordv2Spec.pdf -tmp/data/c7782601-8634-4386-8e33-18b6f9790b33/contents/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [28, 29] -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/g158bh28p -In find_work -In find_work_by_id -In find_work -In find_work_by_id -In find_work -In find_work_by_id -In find_work -In find_work_by_id -In find_work -In find_work_by_id -In find_work -In find_work_by_id -In find_work -In find_work_by_id -saving body -1091 -saving body -1091 -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1091 -File path: tmp/data/9ea94051-e30d-40db-899c-9e1e1c55b604/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1091 -File path: tmp/data/771bf23f-afdd-4a55-b68c-a6ee4869cbfc/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1042 -File path: tmp/data/15bfdd48-6043-481b-81c9-cf2944beef10/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1042 -File path: tmp/data/1152da44-3477-4c7a-816e-a253381cca6f/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1042 -File path: tmp/data/5214c708-f3b3-483c-8ae2-9e2077e3a057/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1042 -File path: tmp/data/91ed677e-870b-4f06-8a77-9b9359b9b991/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -Content type: image/png -Filename: data2paper_screenshot.png -MD5 hash: 605ae7a8a167bf2bfe031bf3f7378012 -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -167697 -File path: tmp/data/61657e2b-63a0-4fab-8f3c-08f65a653b9b/data2paper_screenshot.png -File exists: true -In upload_files -Files uploaded: [30] -Content type: image/png -Filename: data2paper_screenshot.png -MD5 hash: 605ae7a8a167bf2bfe031bf3f7378012 -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -167697 -File path: tmp/data/5da0ce19-ed7a-4be8-ad3a-eaaad156f733/data2paper_screenshot.png -File exists: true -In upload_files -Files uploaded: [31] -In update_work -In update_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/dn39x152w -Content type: application/xml -Filename: metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1182 -File path: tmp/data/427a7a51-e6c8-483e-9882-3fb383189b6b/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["The dublin core generator"], :date_created=>["29/05/2018"], :creator=>["Anusha"], :description=>["This is a test dc record to test the dc crosswalk and creation of a metadata only record"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Title", "Test record with only metadata"], :resource_type=>["Article"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/1g05fb60f -In find_work -In find_work_by_id -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/7e19b6a9-2156-4365-bfe3-b289a151a487/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["John Smith"], :date_created=>["29/05/2018"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/7e19b6a9-2156-4365-bfe3-b289a151a487/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [32] -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/jh343s28d -In find_work -In find_work_by_id -Content type: application/zip -Filename: testPackage2InBagit.zip -MD5 hash: c058e3a3eba263df481ebf69ba2305f7 -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -481460 -File path: tmp/data/cd7b9941-ac94-4374-a2a0-f9f8d36ffb4f/testPackage2InBagit.zip -File exists: true -Content type: application/zip -Filename: testPackage2InBagit.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/BagIt -In progress: -On behalf of: hyrax@testinstance -Slug: -saving body -481460 -File path: tmp/data/e2cdd6f0-9eb8-40c9-9723-0db1439523d2/testPackage2InBagit.zip -File exists: true -Content type: application/zip -Filename: testPackage2InBagit.zip -MD5 hash: 572371fa2ce9e371fbfb87477f8318ec -Packaging http://purl.org/net/sword/package/BagIt -In progress: -On behalf of: hyrax@testinstance -Slug: -saving body -481460 -File path: tmp/data/eb8f9a3d-7794-4fc9-9f77-fccc8b5046b4/testPackage2InBagit.zip -File exists: true -Mime type: application/zip -process zip -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"CC-0", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/eb8f9a3d-7794-4fc9-9f77-fccc8b5046b4/contents/data/images/data2paper.png -tmp/data/eb8f9a3d-7794-4fc9-9f77-fccc8b5046b4/contents/data/Swordv2Spec.pdf -tmp/data/eb8f9a3d-7794-4fc9-9f77-fccc8b5046b4/contents/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [33, 34, 35] -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/z316q156s -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1042 -File path: tmp/data/6c0bc4f7-6b66-4c28-a617-60e3713c5ceb/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -In find_work -In find_work_by_id -Content type: image/png -Filename: data2paper_screenshot.png -MD5 hash: 605ae7a8a167bf2bfe031bf3f7378012 -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -167697 -File path: tmp/data/d6627fa4-800e-4dc2-bfca-332c5f2a97dc/data2paper_screenshot.png -File exists: true -In upload_files -Files uploaded: [36] -In update_work -In update_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/jh343s28d -In find_work -In find_work_by_id -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-06 09:18:12 +0000 === -- Goodbye! -=== puma startup: 2018-07-06 09:43:45 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-06 09:44:28 +0000 === -- Goodbye! -=== puma startup: 2018-07-06 09:44:35 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-06 09:47:34 +0000 === -- Goodbye! -=== puma startup: 2018-07-06 09:48:40 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-09 11:24:20 +0000 === -- Goodbye! -=== puma startup: 2018-07-09 11:24:27 +0000 === -Content type: application/xml -Filename: metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1182 -File path: tmp/data/01cf7adc-6d20-44d1-a1d5-40e5cc0627c2/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["The dublin core generator"], :date_created=>["29/05/2018"], :creator=>["Anusha"], :description=>["This is a test dc record to test the dc crosswalk and creation of a metadata only record"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Title", "Test record with only metadata"], :resource_type=>["Article"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/44558d285 -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-13 11:32:54 +0000 === -- Goodbye! -=== puma startup: 2018-07-13 11:37:10 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-13 11:53:27 +0000 === -- Goodbye! -=== puma startup: 2018-07-13 11:54:20 +0000 === -Default collection -Test record 3 -Title | Test record with only metadata -Test record 3 -Test record -Title | Test record with only metadata -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-16 23:10:09 +0000 === -- Goodbye! -=== puma startup: 2018-07-16 23:11:58 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-16 23:20:54 +0000 === -- Goodbye! -=== puma startup: 2018-07-16 23:21:12 +0000 === -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/1bf84f46-1352-4915-b70c-1b453aca33dd/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -{} --------------------------------------------------- -tmp/data/1bf84f46-1352-4915-b70c-1b453aca33dd/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [42] -In add_work -In find_work -In create_work -In create_attributes -Content type: application/xml -Filename: metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1182 -File path: tmp/data/4fa4338f-9d8f-41f4-93ef-5e1c18da9537/metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["The dublin core generator"], :date_created=>["29/05/2018"], :creator=>["Anusha"], :description=>["This is a test dc record to test the dc crosswalk and creation of a metadata only record"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Title", "Test record with only metadata"], :resource_type=>["Article"]} --------------------------------------------------- --------------------------------------------------- -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/bz60cw24r -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-16 23:30:15 +0000 === -- Goodbye! -=== puma startup: 2018-07-16 23:30:33 +0000 === -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/5821ff20-ea38-47e0-ae59-dd58ae10615d/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -tmp/data/5821ff20-ea38-47e0-ae59-dd58ae10615d/bag/data/metadata.xml -true -{} --------------------------------------------------- -tmp/data/5821ff20-ea38-47e0-ae59-dd58ae10615d/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [43] -In add_work -In find_work -In create_work -In create_attributes -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-16 23:35:29 +0000 === -- Goodbye! -=== puma startup: 2018-07-16 23:35:46 +0000 === -Content type: application/zip -Filename: testPackage3.zip -MD5 hash: -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -283334 -File path: tmp/data/06096ee5-33fd-4290-bec9-78bc940e540b/testPackage3.zip -File exists: true -Mime type: application/zip -process zip -tmp/data/06096ee5-33fd-4290-bec9-78bc940e540b/bag/data/metadata.xml -true -{:contributor=>["John Smith"], :date_created=>["29/05/2018"], :creator=>["Anusha Ranganathan", "Another creator", "Yet another creator"], :description=>["This is a test dc record to test the dc crosswalk"], :identifier=>["pubs:1234"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"Copyright Not Evaluated", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 3"]} --------------------------------------------------- -tmp/data/06096ee5-33fd-4290-bec9-78bc940e540b/bag/data/Swordv2Spec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [44] -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/2z10wq20d -Content type: application/zip -Filename: testPackage2.zip -MD5 hash: fb19c3d7b3429a2a3ab0d4193084cec2 -Packaging http://purl.org/net/sword/package/SimpleZip -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -478979 -File path: tmp/data/b06a394a-6017-410d-9889-3cb5b778bbdf/testPackage2.zip -File exists: true -Mime type: application/zip -process zip -tmp/data/b06a394a-6017-410d-9889-3cb5b778bbdf/bag/data/metadata.xml -true -{:contributor=>["The dublin core generator"], :creator=>["Anusha"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"CC-0", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record"]} --------------------------------------------------- -tmp/data/b06a394a-6017-410d-9889-3cb5b778bbdf/bag/data/images/data2paper.png -tmp/data/b06a394a-6017-410d-9889-3cb5b778bbdf/bag/data/Swordv2Spec.pdf -tmp/data/b06a394a-6017-410d-9889-3cb5b778bbdf/bag/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [45, 46, 47] -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/x059c7329 -Content type: application/zip -Filename: testPackage1InBagit.zip -MD5 hash: c058e3a3eba263df481ebf69ba2305f7 -Packaging http://purl.org/net/sword/package/BagIt -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -324668 -File path: tmp/data/09557d64-c966-483b-a5bd-039f09fca2ef/testPackage1InBagit.zip -File exists: true -Mime type: application/zip -process zip -tmp/data/09557d64-c966-483b-a5bd-039f09fca2ef/contents/data/metadata.xml -true -{:contributor=>["The dublin core generator"], :creator=>["Anusha Ranganathan", "Another creator"], :date=>["29/05/2018"], :description=>["This is a test dc record to test the dc crosswalk"], :language=>["English"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :rights_statement=>"CC-0", :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Test record 1"]} --------------------------------------------------- -tmp/data/09557d64-c966-483b-a5bd-039f09fca2ef/contents/data/Swordv2Spec.pdf -tmp/data/09557d64-c966-483b-a5bd-039f09fca2ef/contents/data/bagitSpec.pdf --------------------------------------------------- -In upload_files -Files uploaded: [48, 49] -In add_work -In find_work -In create_work -In create_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/5425k968s -In find_work -In find_work_by_id -In find_work -In find_work_by_id -Content type: image/png -Filename: data2paper_screenshot.png -MD5 hash: 605ae7a8a167bf2bfe031bf3f7378012 -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -167697 -File path: tmp/data/2116f5fd-e994-4e05-872a-92c44ad30f46/data2paper_screenshot.png -File exists: true -In upload_files -Files uploaded: [50] -In update_work -In update_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/dn39x152w -In find_work -In find_work_by_id -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1042 -File path: tmp/data/5dd4c71e-89bb-496b-a58b-14ddbfffff67/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -In find_work -In find_work_by_id -In find_work -In find_work_by_id -In find_work -In find_work_by_id -Content type: image/png -Filename: data2paper_screenshot.png -MD5 hash: 605ae7a8a167bf2bfe031bf3f7378012 -Packaging http://purl.org/net/sword/package/Binary -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -167697 -File path: tmp/data/3d990967-714c-40f8-bfb3-67343155f7c1/data2paper_screenshot.png -File exists: true -In upload_files -Files uploaded: [51] -In update_work -In update_attributes -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/5425k968s -Content type: application/xml -Filename: file_metadata.xml -MD5 hash: -Packaging application/atom+xml;type=entry -In progress: false -On behalf of: hyrax@testinstance -Slug: -saving body -1042 -File path: tmp/data/e774c8f1-8267-4ca7-9c77-b207aad92d9a/file_metadata.xml -File exists: true -Mime type: application/xml -process xml -{:contributor=>["Data2pper team"], :date_created=>["29/05/2018"], :creator=>["Richard Jones"], :description=>["This is a test file. The description is being updated"], :identifier=>["pubs:12345678"], :language=>["English"], :license=>["https://creativecommons.org/licenses/by/4.0/"], :publisher=>["Digital Nest"], :related_url=>["http://example.com"], :source=>["http://sword.digitalnest.com"], :subject=>["Sword", "Crosswalk"], :title=>["Sword V2 Specification document", "Sword V2 Specification document"]} --------------------------------------------------- --------------------------------------------------- -In find_file_set -In find_file_set_by_id -In update_file_set -In file_set_update_attributes -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-17 01:43:01 +0000 === -- Goodbye! -=== puma startup: 2018-07-17 01:43:19 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-17 01:44:47 +0000 === -- Goodbye! -=== puma startup: 2018-07-17 01:45:05 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-17 02:00:14 +0000 === -- Goodbye! -=== puma startup: 2018-07-17 02:00:31 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-17 02:14:54 +0000 === -- Goodbye! -=== puma startup: 2018-07-17 02:15:12 +0000 === -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/cf95jb44s -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-18 22:58:35 +0000 === -- Goodbye! -=== puma startup: 2018-07-18 22:58:53 +0000 === -Model: Collection -Model: Collection -Model: -Model: -Model: -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-18 23:23:53 +0000 === -- Goodbye! -=== puma startup: 2018-07-18 23:24:10 +0000 === -Model: -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-18 23:25:29 +0000 === -- Goodbye! -=== puma startup: 2018-07-18 23:26:39 +0000 === -Model: -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-18 23:29:53 +0000 === -- Goodbye! -=== puma startup: 2018-07-18 23:30:11 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-18 23:34:03 +0000 === -- Goodbye! -=== puma startup: 2018-07-18 23:34:21 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-18 23:36:32 +0000 === -- Goodbye! -=== puma startup: 2018-07-18 23:37:28 +0000 === -Work models: ["Work"] -Work models: ["Work"] -Work models: ["Work"] -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-07-18 23:56:58 +0000 === -- Goodbye! -=== puma startup: 2018-07-18 23:57:15 +0000 === -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/dn39x152w -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/dn39x152w -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/k35694332 -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/k35694332 -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/st74cq441 -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/ks65hc20t -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/j3860693n -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/n296wz12m -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/t722h880z -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/f4752g72m -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/gq67jr16q -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/0c483j36g -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/7h149p84n -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/nk322d33s -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/8p58pc92q -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/k35694332 -URL http://hyrax.digitalnest.co.uk/sword/collections/col1/works/k35694332 -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/b8515n370 -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/h702q6382 -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/j9602060k -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/j9602060k -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/sj139192w -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/sj139192w -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/z603qx40z -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/kd17cs845 -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/7m01bk68h -URL http://hyrax.digitalnest.co.uk/sword/collections/default/works/fb4948403 -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-11-05 12:13:01 +0000 === -- Goodbye! -=== puma startup: 2018-11-05 12:30:53 +0000 === -- Gracefully stopping, waiting for requests to finish -=== puma shutdown: 2018-11-05 12:39:59 +0000 === -- Goodbye! -=== puma startup: 2018-11-05 12:40:50 +0000 === diff --git a/hyrax/shared/pids/.keep b/hyrax/shared/pids/.keep new file mode 100644 index 00000000..2e9fdd62 --- /dev/null +++ b/hyrax/shared/pids/.keep @@ -0,0 +1 @@ +# Required for puma hyrax/config/puma.rb \ No newline at end of file diff --git a/hyrax/shared/pids/puma.pid b/hyrax/shared/pids/puma.pid deleted file mode 100644 index 955a6c17..00000000 --- a/hyrax/shared/pids/puma.pid +++ /dev/null @@ -1 +0,0 @@ -7515 diff --git a/hyrax/shared/pids/puma.state b/hyrax/shared/pids/puma.state deleted file mode 100644 index eb492de9..00000000 --- a/hyrax/shared/pids/puma.state +++ /dev/null @@ -1,4 +0,0 @@ ---- -pid: 7515 -control_url: unix:///tmp/puma-status-1541421630551-7515 -control_auth_token: c0e0b4a54185731341f949bd4c1596a diff --git a/hyrax/shared/sockets/.keep b/hyrax/shared/sockets/.keep new file mode 100644 index 00000000..2e9fdd62 --- /dev/null +++ b/hyrax/shared/sockets/.keep @@ -0,0 +1 @@ +# Required for puma hyrax/config/puma.rb \ No newline at end of file diff --git a/hyrax/solr/conf/_rest_managed.json b/hyrax/solr/conf/_rest_managed.json deleted file mode 100644 index e7ada3f6..00000000 --- a/hyrax/solr/conf/_rest_managed.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "initArgs":{}, - "managedList":[]} \ No newline at end of file diff --git a/hyrax/solr/conf/admin-extra.html b/hyrax/solr/conf/admin-extra.html deleted file mode 100644 index 21b50901..00000000 --- a/hyrax/solr/conf/admin-extra.html +++ /dev/null @@ -1,31 +0,0 @@ - - - diff --git a/hyrax/solr/conf/elevate.xml b/hyrax/solr/conf/elevate.xml deleted file mode 100644 index b91e75ce..00000000 --- a/hyrax/solr/conf/elevate.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/hyrax/solr/conf/mapping-ISOLatin1Accent.txt b/hyrax/solr/conf/mapping-ISOLatin1Accent.txt deleted file mode 100644 index 186ca313..00000000 --- a/hyrax/solr/conf/mapping-ISOLatin1Accent.txt +++ /dev/null @@ -1,246 +0,0 @@ -# The ASF licenses this file to You 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. - -# Syntax: -# "source" => "target" -# "source".length() > 0 (source cannot be empty.) -# "target".length() >= 0 (target can be empty.) - -# example: -# "??" => "A" -# "\u00C0" => "A" -# "\u00C0" => "\u0041" -# "??" => "ss" -# "\t" => " " -# "\n" => "" - -# ?? => A -"\u00C0" => "A" - -# ?? => A -"\u00C1" => "A" - -# ?? => A -"\u00C2" => "A" - -# ?? => A -"\u00C3" => "A" - -# ?? => A -"\u00C4" => "A" - -# ?? => A -"\u00C5" => "A" - -# ?? => AE -"\u00C6" => "AE" - -# ?? => C -"\u00C7" => "C" - -# ?? => E -"\u00C8" => "E" - -# ?? => E -"\u00C9" => "E" - -# ?? => E -"\u00CA" => "E" - -# ?? => E -"\u00CB" => "E" - -# ?? => I -"\u00CC" => "I" - -# ?? => I -"\u00CD" => "I" - -# ?? => I -"\u00CE" => "I" - -# ?? => I -"\u00CF" => "I" - -# ?? => IJ -"\u0132" => "IJ" - -# ?? => D -"\u00D0" => "D" - -# ?? => N -"\u00D1" => "N" - -# ?? => O -"\u00D2" => "O" - -# ?? => O -"\u00D3" => "O" - -# ?? => O -"\u00D4" => "O" - -# ?? => O -"\u00D5" => "O" - -# ?? => O -"\u00D6" => "O" - -# ?? => O -"\u00D8" => "O" - -# ?? => OE -"\u0152" => "OE" - -# ?? -"\u00DE" => "TH" - -# ?? => U -"\u00D9" => "U" - -# ?? => U -"\u00DA" => "U" - -# ?? => U -"\u00DB" => "U" - -# ?? => U -"\u00DC" => "U" - -# ?? => Y -"\u00DD" => "Y" - -# ?? => Y -"\u0178" => "Y" - -# ?? => a -"\u00E0" => "a" - -# ?? => a -"\u00E1" => "a" - -# ?? => a -"\u00E2" => "a" - -# ?? => a -"\u00E3" => "a" - -# ?? => a -"\u00E4" => "a" - -# ?? => a -"\u00E5" => "a" - -# ?? => ae -"\u00E6" => "ae" - -# ?? => c -"\u00E7" => "c" - -# ?? => e -"\u00E8" => "e" - -# ?? => e -"\u00E9" => "e" - -# ?? => e -"\u00EA" => "e" - -# ?? => e -"\u00EB" => "e" - -# ?? => i -"\u00EC" => "i" - -# ?? => i -"\u00ED" => "i" - -# ?? => i -"\u00EE" => "i" - -# ?? => i -"\u00EF" => "i" - -# ?? => ij -"\u0133" => "ij" - -# ?? => d -"\u00F0" => "d" - -# ?? => n -"\u00F1" => "n" - -# ?? => o -"\u00F2" => "o" - -# ?? => o -"\u00F3" => "o" - -# ?? => o -"\u00F4" => "o" - -# ?? => o -"\u00F5" => "o" - -# ?? => o -"\u00F6" => "o" - -# ?? => o -"\u00F8" => "o" - -# ?? => oe -"\u0153" => "oe" - -# ?? => ss -"\u00DF" => "ss" - -# ?? => th -"\u00FE" => "th" - -# ?? => u -"\u00F9" => "u" - -# ?? => u -"\u00FA" => "u" - -# ?? => u -"\u00FB" => "u" - -# ?? => u -"\u00FC" => "u" - -# ?? => y -"\u00FD" => "y" - -# ?? => y -"\u00FF" => "y" - -# ??? => ff -"\uFB00" => "ff" - -# ??? => fi -"\uFB01" => "fi" - -# ??? => fl -"\uFB02" => "fl" - -# ??? => ffi -"\uFB03" => "ffi" - -# ??? => ffl -"\uFB04" => "ffl" - -# ??? => ft -"\uFB05" => "ft" - -# ??? => st -"\uFB06" => "st" diff --git a/hyrax/solr/conf/protwords.txt b/hyrax/solr/conf/protwords.txt deleted file mode 100644 index 5a32e503..00000000 --- a/hyrax/solr/conf/protwords.txt +++ /dev/null @@ -1,21 +0,0 @@ -# The ASF licenses this file to You 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. - -#----------------------------------------------------------------------- -# Use a protected word file to protect against the stemmer reducing two -# unrelated words to the same base word. - -# Some non-words that normally won't be encountered, -# just to test that they won't be stemmed. -dontstems -zwhacky - diff --git a/hyrax/solr/conf/schema.xml b/hyrax/solr/conf/schema.xml deleted file mode 100644 index 7ec14871..00000000 --- a/hyrax/solr/conf/schema.xml +++ /dev/null @@ -1,629 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - id - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hyrax/solr/conf/scripts.conf b/hyrax/solr/conf/scripts.conf deleted file mode 100644 index f58b262a..00000000 --- a/hyrax/solr/conf/scripts.conf +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -user= -solr_hostname=localhost -solr_port=8983 -rsyncd_port=18983 -data_dir= -webapp_name=solr -master_host= -master_data_dir= -master_status_dir= diff --git a/hyrax/solr/conf/solrconfig.xml b/hyrax/solr/conf/solrconfig.xml deleted file mode 100644 index eba6cc93..00000000 --- a/hyrax/solr/conf/solrconfig.xml +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - - - 5.0.0 - - - - - - - - - - - - - ${solr.blacklight-core.data.dir:} - - - - - - - - - - *:* - - - - - - - dismax - explicit - 10 - - *:* - 2<-1 5<-2 6<90% - - - - - title_unstem_search^100000 - subtitle_unstem_search^50000 - title_t^25000 - subtitle_t^10000 - title_addl_unstem_search^5000 - title_addl_t^2500 - title_added_entry_unstem_search^1500 - title_added_entry_t^1250 - subject_topic_unstem_search^1000 - subject_unstem_search^750 - subject_topic_facet^625 - subject_t^500 - author_unstem_search^250 - author_addl_unstem_search^250 - author_t^100 - author_addl_t^50 - subject_addl_unstem_search^250 - subject_addl_t^50 - title_series_unstem_search^25 - title_series_t^10 - isbn_t - text - - - title_unstem_search^1000000 - subtitle_unstem_search^500000 - title_t^250000 - subtitle_t^100000 - title_addl_unstem_search^50000 - title_addl_t^25000 - title_added_entry_unstem_search^15000 - title_added_entry_t^12500 - subject_topic_unstem_search^10000 - subject_unstem_search^7500 - subject_topic_facet^6250 - subject_t^5000 - author_unstem_search^2500 - author_addl_unstem_search^2500 - author_t^1000 - author_addl_t^500 - subject_addl_unstem_search^2500 - subject_addl_t^500 - title_series_unstem_search^250 - title_series_t^100 - text^10 - - - author_unstem_search^200 - author_addl_unstem_search^50 - author_t^20 - author_addl_t - - - author_unstem_search^2000 - author_addl_unstem_search^500 - author_t^200 - author_addl_t^10 - - - title_unstem_search^50000 - subtitle_unstem_search^25000 - title_addl_unstem_search^10000 - title_t^5000 - subtitle_t^2500 - title_addl_t^100 - title_added_entry_unstem_search^50 - title_added_entry_t^10 - title_series_unstem_search^5 - title_series_t - - - title_unstem_search^500000 - subtitle_unstem_search^250000 - title_addl_unstem_search^100000 - title_t^50000 - subtitle_t^25000 - title_addl_t^1000 - title_added_entry_unstem_search^500 - title_added_entry_t^100 - title_series_t^50 - title_series_unstem_search^10 - - - subject_topic_unstem_search^200 - subject_unstem_search^125 - subject_topic_facet^100 - subject_t^50 - subject_addl_unstem_search^10 - subject_addl_t - - - subject_topic_unstem_search^2000 - subject_unstem_search^1250 - subject_t^1000 - subject_topic_facet^500 - subject_addl_unstem_search^100 - subject_addl_t^10 - - - 3 - 0.01 - - - - id, - score, - author_display, - author_vern_display, - format, - isbn_t, - language_facet, - lc_callnum_display, - material_type_display, - published_display, - published_vern_display, - pub_date, - title_display, - title_vern_display, - subject_topic_facet, - subject_geo_facet, - subject_era_facet, - subtitle_display, - subtitle_vern_display, - url_fulltext_display, - url_suppl_display, - - - true - 1 - format - lc_1letter_facet - lc_alpha_facet - lc_b4cutter_facet - language_facet - pub_date - subject_era_facet - subject_geo_facet - subject_topic_facet - - true - default - true - true - false - 5 - - - - - - - - - - - spellcheck - - - - - - - - all - * - 1 - {!term f=id v=$id} - - - - - - - textSpell - - - - - - default - spell - ./spell - true - - - author - author_spell - ./spell_author - 0.7 - true - - - subject - subject_spell - ./spell_subject - 0.7 - true - - - title - title_spell - ./spell_title - 0.7 - true - - - - - - - - - - - - - - - mySuggester - FuzzyLookupFactory - textSuggest - true - suggest - - - - - - true - 5 - mySuggester - - - suggest - - - - - diff --git a/hyrax/solr/conf/spellings.txt b/hyrax/solr/conf/spellings.txt deleted file mode 100644 index 765190ae..00000000 --- a/hyrax/solr/conf/spellings.txt +++ /dev/null @@ -1,2 +0,0 @@ -pizza -history diff --git a/hyrax/solr/conf/stopwords.txt b/hyrax/solr/conf/stopwords.txt deleted file mode 100644 index 22f277fe..00000000 --- a/hyrax/solr/conf/stopwords.txt +++ /dev/null @@ -1,58 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -#----------------------------------------------------------------------- -# a couple of test stopwords to test that the words are really being -# configured from this file: -stopworda -stopwordb - -#Standard english stop words taken from Lucene's StopAnalyzer -a -an -and -are -as -at -be -but -by -for -if -in -into -is -it -no -not -of -on -or -s -such -t -that -the -their -then -there -these -they -this -to -was -will -with - diff --git a/hyrax/solr/conf/stopwords_en.txt b/hyrax/solr/conf/stopwords_en.txt deleted file mode 100644 index 22f277fe..00000000 --- a/hyrax/solr/conf/stopwords_en.txt +++ /dev/null @@ -1,58 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -#----------------------------------------------------------------------- -# a couple of test stopwords to test that the words are really being -# configured from this file: -stopworda -stopwordb - -#Standard english stop words taken from Lucene's StopAnalyzer -a -an -and -are -as -at -be -but -by -for -if -in -into -is -it -no -not -of -on -or -s -such -t -that -the -their -then -there -these -they -this -to -was -will -with - diff --git a/hyrax/solr/conf/synonyms.txt b/hyrax/solr/conf/synonyms.txt deleted file mode 100644 index 453eb313..00000000 --- a/hyrax/solr/conf/synonyms.txt +++ /dev/null @@ -1,31 +0,0 @@ -# The ASF licenses this file to You 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. - -#----------------------------------------------------------------------- -#some test synonym mappings unlikely to appear in real input text -aaa => aaaa -bbb => bbbb1 bbbb2 -ccc => cccc1,cccc2 -a\=>a => b\=>b -a\,a => b\,b -fooaaa,baraaa,bazaaa - -# Some synonym groups specific to this example -GB,gib,gigabyte,gigabytes -MB,mib,megabyte,megabytes -Television, Televisions, TV, TVs -#notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming -#after us won't split it into two words. - -# Synonym mappings can be used for spelling correction too -pixima => pixma - diff --git a/hyrax/solr/conf/xslt/example.xsl b/hyrax/solr/conf/xslt/example.xsl deleted file mode 100644 index ff7cae74..00000000 --- a/hyrax/solr/conf/xslt/example.xsl +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - <xsl:value-of select="$title"/> - - - -

    -
    - This has been formatted by the sample "example.xsl" transform - - use your own XSLT to get a nicer page -
    - - - -
    - - - -
    - - - - -
    -
    -
    - - - - - - - - - - - - - - javascript:toggle("");? -
    - - exp - - - - - -
    - - -
    - - - - - - - -
      - -
    • -
      -
    - - -
    - - - - - - - - - - - - - - - - - - - - -
    diff --git a/hyrax/solr/conf/xslt/example_atom.xsl b/hyrax/solr/conf/xslt/example_atom.xsl deleted file mode 100644 index dbc7afa3..00000000 --- a/hyrax/solr/conf/xslt/example_atom.xsl +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - Example Solr Atom 1.0 Feed - - This has been formatted by the sample "example_atom.xsl" transform - - use your own XSLT to get a nicer Atom feed. - - - Apache Solr - solr-user@lucene.apache.org - - - - - - tag:localhost,2007:example - - - - - - - - - <xsl:value-of select="str[@name='name']"/> - - tag:localhost,2007: - - - - - - diff --git a/hyrax/solr/conf/xslt/example_rss.xsl b/hyrax/solr/conf/xslt/example_rss.xsl deleted file mode 100644 index b5bd0cf9..00000000 --- a/hyrax/solr/conf/xslt/example_rss.xsl +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - Example Solr RSS 2.0 Feed - http://localhost:8983/solr - - This has been formatted by the sample "example_rss.xsl" transform - - use your own XSLT to get a nicer RSS feed. - - en-us - http://localhost:8983/solr - - - - - - - - - - - <xsl:value-of select="str[@name='name']"/> - - http://localhost:8983/solr/select?q=id: - - - - - - - http://localhost:8983/solr/select?q=id: - - - - diff --git a/hyrax/solr/conf/xslt/luke.xsl b/hyrax/solr/conf/xslt/luke.xsl deleted file mode 100644 index d3f71c6d..00000000 --- a/hyrax/solr/conf/xslt/luke.xsl +++ /dev/null @@ -1,337 +0,0 @@ - - - - - - - - - Solr Luke Request Handler Response - - - - - - - - - <xsl:value-of select="$title"/> - - - - - -

    - -

    -
    - -
    - -

    Index Statistics

    - -
    - -

    Field Statistics

    - - - -

    Document statistics

    - - - - -
    - - - - - -
    - -
    - - -
    - -
    - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - -
    -

    - -

    - -
    - -
    -
    -
    - - -
    - - 50 - 800 - 160 - blue - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - background-color: ; width: px; height: px; -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - -
    • - -
    • -
      -
    - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    diff --git a/hyrax/solr/config/schema.xml b/hyrax/solr/config/schema.xml index 8eda5703..f5895a05 100644 --- a/hyrax/solr/config/schema.xml +++ b/hyrax/solr/config/schema.xml @@ -48,43 +48,47 @@ - + - + - - - - - - - - - - - + + + + + + + + + + + - - - - - + + + + + + - - - - - - + @@ -112,7 +113,7 @@ - + @@ -120,7 +121,7 @@ - + @@ -129,7 +130,7 @@ - + @@ -144,7 +145,7 @@ - + @@ -154,7 +155,7 @@ - + @@ -168,7 +169,6 @@ - @@ -179,12 +179,12 @@ + --> - + - + @@ -201,7 +201,7 @@ - + @@ -213,7 +213,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -230,15 +230,15 @@ - - + + - + @@ -248,15 +248,24 @@ - - + + - + + + + + + + + + + @@ -264,15 +273,15 @@ - - + + - + @@ -280,15 +289,15 @@ - - + + - + @@ -296,31 +305,23 @@ - - + + - + - + - - - - - - - - @@ -329,7 +330,7 @@ - id diff --git a/hyrax/solr/config/solrconfig.xml b/hyrax/solr/config/solrconfig.xml index fe85af77..8aadbef9 100644 --- a/hyrax/solr/config/solrconfig.xml +++ b/hyrax/solr/config/solrconfig.xml @@ -284,6 +284,8 @@ --> + + + last_modified diff --git a/hyrax/spec/actors/hyrax/actors/complex_attributes_spec.rb b/hyrax/spec/actors/hyrax/actors/complex_attributes_spec.rb new file mode 100644 index 00000000..13e74ce2 --- /dev/null +++ b/hyrax/spec/actors/hyrax/actors/complex_attributes_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe Hyrax::Actors::ComplexAttributes do + let(:env) { double(curation_concern: double(updated_subresources: [], :updated_subresources= => []) ) } + + before do + class SuperClass + def apply_save_data_to_curation_concern(env) + end + end + + class TestClass < SuperClass + include Hyrax::Actors::ComplexAttributes + end + + class ExampleWork < ActiveFedora::Base + property :complex_version, predicate: ::RDF::URI.new('http://www.w3.org/2002/07/owl#versionInfo'), class_name: "ComplexVersion" + accepts_nested_attributes_for :complex_version + end + end + + after do + Object.send(:remove_const, :ExampleWork) + Object.send(:remove_const, :TestClass) + Object.send(:remove_const, :SuperClass) + end + + let(:test) { TestClass.new } + + describe '#apply_save_data_to_curation_concern' do + before { test.apply_save_data_to_curation_concern(env) } + it { expect(env.curation_concern).to have_received(:updated_subresources=).with([]) } + end + + describe '#update_complex_metadata' do + let(:resource) { double(complex_version: ExampleWork.new(complex_version_attributes: [{ version: '1.0' }]).complex_version) } + before { test.update_complex_metadata(env, resource) } + it { expect(env.curation_concern.updated_subresources).to eql([resource.complex_version]) } + end + + describe '#complex_attributes' do + subject { test.complex_attributes } + it { is_expected.to match_array(%w[complex_person complex_identifier complex_rights complex_organization complex_date custom_property + complex_specimen_type complex_version complex_relation complex_instrument complex_affiliation manufacturer managing_organization + supplier custom_property complex_structural_feature complex_state_of_matter complex_shape complex_purchase_record + complex_material_type instrument_function complex_chemical_composition complex_crystallographic_structure + complex_event complex_source complex_event_date]) } + end +end diff --git a/hyrax/spec/actors/hyrax/actors/dataset_actor_spec.rb b/hyrax/spec/actors/hyrax/actors/dataset_actor_spec.rb new file mode 100644 index 00000000..55ed0404 --- /dev/null +++ b/hyrax/spec/actors/hyrax/actors/dataset_actor_spec.rb @@ -0,0 +1,7 @@ +# Generated via +# `rails generate hyrax:work Dataset` +require 'rails_helper' + +RSpec.describe Hyrax::Actors::DatasetActor do + it { expect(described_class).to be < Hyrax::Actors::BaseActor } +end diff --git a/hyrax/spec/actors/hyrax/actors/image_actor_spec.rb b/hyrax/spec/actors/hyrax/actors/image_actor_spec.rb new file mode 100644 index 00000000..bcff197b --- /dev/null +++ b/hyrax/spec/actors/hyrax/actors/image_actor_spec.rb @@ -0,0 +1,7 @@ +# Generated via +# `rails generate hyrax:work Image` +require 'rails_helper' + +RSpec.describe Hyrax::Actors::ImageActor do + it { expect(described_class).to be < Hyrax::Actors::BaseActor } +end diff --git a/hyrax/spec/actors/hyrax/actors/publication_actor_spec.rb b/hyrax/spec/actors/hyrax/actors/publication_actor_spec.rb new file mode 100644 index 00000000..0fd277c0 --- /dev/null +++ b/hyrax/spec/actors/hyrax/actors/publication_actor_spec.rb @@ -0,0 +1,7 @@ +# Generated via +# `rails generate hyrax:work Publication` +require 'rails_helper' + +RSpec.describe Hyrax::Actors::PublicationActor do + it { expect(described_class).to be < Hyrax::Actors::BaseActor } +end diff --git a/hyrax/spec/actors/hyrax/actors/work_actor_spec.rb b/hyrax/spec/actors/hyrax/actors/work_actor_spec.rb index bd79160f..74163d5e 100644 --- a/hyrax/spec/actors/hyrax/actors/work_actor_spec.rb +++ b/hyrax/spec/actors/hyrax/actors/work_actor_spec.rb @@ -3,7 +3,5 @@ require 'rails_helper' RSpec.describe Hyrax::Actors::WorkActor do - it "has tests" do - skip "Add your tests here" - end + it { expect(described_class).to be < Hyrax::Actors::BaseActor } end diff --git a/hyrax/spec/channels/application_cable/channel_spec.rb b/hyrax/spec/channels/application_cable/channel_spec.rb new file mode 100644 index 00000000..337dba98 --- /dev/null +++ b/hyrax/spec/channels/application_cable/channel_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ::ApplicationCable::Channel do + it { expect(described_class).to be < ActionCable::Channel::Base } +end diff --git a/hyrax/spec/channels/application_cable/connection_spec.rb b/hyrax/spec/channels/application_cable/connection_spec.rb new file mode 100644 index 00000000..2ab5470f --- /dev/null +++ b/hyrax/spec/channels/application_cable/connection_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ::ApplicationCable::Connection do + it { expect(described_class).to be < ActionCable::Connection::Base } +end diff --git a/hyrax/spec/controllers/hyrax/datasets_controller_spec.rb b/hyrax/spec/controllers/hyrax/datasets_controller_spec.rb new file mode 100644 index 00000000..db10c1ce --- /dev/null +++ b/hyrax/spec/controllers/hyrax/datasets_controller_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Dataset` +require 'rails_helper' + +RSpec.describe Hyrax::DatasetsController do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/controllers/hyrax/exports_controller_spec.rb b/hyrax/spec/controllers/hyrax/exports_controller_spec.rb new file mode 100644 index 00000000..9000f2fd --- /dev/null +++ b/hyrax/spec/controllers/hyrax/exports_controller_spec.rb @@ -0,0 +1,71 @@ +require 'rails_helper' +require 'devise' + +RSpec.describe ExportsController do + include Devise::Test::ControllerHelpers + + describe '#export' do + let(:response) { get :export, params: {id: file_set.id} } + let(:status) { response.status } + let(:json) { JSON.parse(response.body) } + + context 'no file' do + let(:file_set) { create(:file_set, :open) } + it 'should return an error' do + expect(status).to eql(400) + expect(json['error']).to eql('Unknown or unsupported file type') + end + end + + context 'non-csv' do + let(:file_set) { create(:file_set, :open, content: File.open(fixture_path + '/xml/other.txt')) } + it 'should return an error' do + expect(status).to eql(400) + expect(json['error']).to eql('Unknown or unsupported file type') + end + end + + context 'csv' do + context 'open' do + let(:file_set) { create(:file_set, :open, content: File.open(fixture_path + '/csv/example.csv')) } + it 'should return a json export of the CSV file' do + expect(status).to eql(200) + expect(json['columns']).to match_array(["Code", "Study_participation", "Census_usually_resident_population_count"]) + expect(json['data']).to match_array([ + ["1", "Full-time study", "1000911"], + ["2", "Part-time study", "149919"], + ["4", "Not studying", "3548922"], + ["7", "Response not identifiable", "0"], + ["9", "Not stated", "0"], + ["TotalStated", "Total stated", "4699755"], + ["Total", "Total", "4699755"] + ]) + expect(json['total_rows']).to eql(7) + expect(json['maximum_rows']).to eql(100) + expect(json['file_name']).to eql("example.csv") + end + end + + describe 'authentication' do + let(:file_set) { create(:file_set, :authenticated, content: File.open(fixture_path + '/csv/example.csv')) } + + context 'unauthenticated' do + it 'should return an unauthenticated error' do + expect(status).to eql(401) + end + end + + context 'authenticated' do + let(:user) { create(:user) } + before do + sign_in user + end + + it 'should return success' do + expect(status).to eql(200) + end + end + end + end + end +end diff --git a/hyrax/spec/controllers/hyrax/file_sets_controller_spec.rb b/hyrax/spec/controllers/hyrax/file_sets_controller_spec.rb new file mode 100644 index 00000000..292bf4b7 --- /dev/null +++ b/hyrax/spec/controllers/hyrax/file_sets_controller_spec.rb @@ -0,0 +1,42 @@ +require 'rails_helper' +require 'devise' + +RSpec.describe Hyrax::FileSetsController do + include Devise::Test::ControllerHelpers + + routes { Rails.application.routes } + let(:user) { create(:user) } + let(:actor) { controller.send(:actor) } + + context 'when signed in' do + before do + sign_in user + end + + describe '#update' do + let(:file_set) do + create(:file_set, user: user) + end + + context 'when updating the attached file version' do + before do + allow(Hyrax::Actors::FileActor).to receive(:new).and_return(actor) + end + + it 'returns a Hyrax::UploadedFile' do + expect(actor).to receive(:update_content).with( + instance_of(Hyrax::UploadedFile) + ).and_return(true) + file = fixture_file_upload('/xml/other.txt', 'text/plain') + post :update, params: { + id: file_set, + file_set: { + files: [file], + permissions_attributes: [{ type: 'person', name: user.username, access: 'edit' }] + } + } + end + end + end + end +end diff --git a/hyrax/spec/controllers/hyrax/images_controller_spec.rb b/hyrax/spec/controllers/hyrax/images_controller_spec.rb new file mode 100644 index 00000000..0ffe86f0 --- /dev/null +++ b/hyrax/spec/controllers/hyrax/images_controller_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Image` +require 'rails_helper' + +RSpec.describe Hyrax::ImagesController do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/controllers/hyrax/publications_controller_spec.rb b/hyrax/spec/controllers/hyrax/publications_controller_spec.rb new file mode 100644 index 00000000..99cca286 --- /dev/null +++ b/hyrax/spec/controllers/hyrax/publications_controller_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Publication` +require 'rails_helper' + +RSpec.describe Hyrax::PublicationsController do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/factories/dataset.rb b/hyrax/spec/factories/dataset.rb new file mode 100644 index 00000000..877ff4c2 --- /dev/null +++ b/hyrax/spec/factories/dataset.rb @@ -0,0 +1,356 @@ +FactoryBot.define do + + factory :dataset do + title { ["Dataset"] } + access_control + + trait :open do + visibility { 'open' } + title { ["Open Dataset"] } + end + + trait :authenticated do + visibility { 'authenticated' } + title { ["Authenticated Dataset"] } + end + + trait :embargo do + visibility { 'embargo' } + title { ["Embargo Dataset"] } + end + + trait :lease do + visibility { 'lease' } + title { ["Leased Dataset"] } + end + + trait :restricted do + visibility { 'restricted' } + title { ["Restricted Dataset"] } + end + + trait :with_description_seq do + sequence(:description) { |n| ["Abstract-Description-#{n}"] } + end + + trait :with_alternative_title do + alternative_title { 'Alternative-Title-123' } + end + + trait :with_keyword do + keyword { ['Keyword-123'] } + end + + trait :with_keyword_seq do + sequence(:keyword) { |n| ["Keyword-#{n}"] } + end + + trait :with_subject do + subject { ['Subject-123'] } + end + + trait :with_subject_seq do + sequence(:subject) { |n| ["Subject-#{n}"] } + end + + trait :with_language do + language { ['Faroese'] } + end + + trait :with_publisher do + publisher { ['Publisher-123'] } + end + + trait :with_resource_type do + resource_type { ['Resource-Type-123'] } + end + + trait :with_source do + source { ['Source-123'] } + end + + trait :with_complex_person do + complex_person_attributes { + [{ + name: 'Anamika', + role: ['operator'], + complex_identifier_attributes: [{ + identifier: '123456', + scheme: 'identifier local' + }], + complex_affiliation_attributes: [{ + job_title: 'Principal Investigator', + complex_organization_attributes: [{ + organization: 'University', + sub_organization: 'Department', + purpose: 'Research' + }] + }] + }] + } + end + + trait :with_complex_author do + complex_person_attributes { + [{ + name: 'Anamika', + role: ['author'], + complex_identifier_attributes: [{ + identifier: '123456', + scheme: 'identifier local' + }], + complex_affiliation_attributes: [{ + job_title: 'Principal Investigator', + complex_organization_attributes: [{ + organization: 'University', + sub_organization: 'Department', + purpose: 'Research' + }] + }] + }] + } + end + + trait :with_complex_chemical_composition do + complex_specimen_type_attributes { + [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + complex_identifier_attributes: [{ + identifier: 'chemical_composition/1234567', + scheme: 'identifier persistent' + }] + }] + }] + } + end + + trait :with_complex_crystallographic_structure do + complex_specimen_type_attributes { + [{ + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + complex_identifier_attributes: [{ + identifier: ['crystallographic_structure/123456'], + scheme: 'identifier persistent' + }] + }] + }] + } + end + + trait :with_custom_property do + custom_property_attributes { + [{ + label: 'Full name', + description: 'Foo Bar' + }] + } + end + + trait :with_complex_date do + complex_date_attributes { + [{ + date: '1978-10-28', + description: 'Published' + }] + } + end + + trait :with_complex_identifier do + complex_identifier_attributes { + [{ + identifier: '10.0.1111', + scheme: 'DOI' + }] + } + end + + trait :with_complex_instrument do + complex_instrument_attributes { + [{ + alternative_title: 'An instrument title', + complex_date_attributes: [{ + date: '2018-02-14', + description: 'Published' + }], + description: 'Instrument description', + complex_identifier_attributes: [{ + identifier: 'instrument/27213727', + scheme: 'identifier persistent', + label: 'Identifier Persistent' + }], + instrument_function_attributes: [{ + column_number: 1, + category: 'some value', + sub_category: 'some other value', + description: 'Instrument function description' + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: '123456789m', + scheme: 'Local' + }] + }], + model_number: '123xfty', + complex_person_attributes: [{ + name: ['Name of operator'], + role: ['operator'], + complex_identifier_attributes: [{ + identifier: '123456789mo', + scheme: 'identifier local' + }], + complex_affiliation_attributes: [{ + job_title: 'Principal Investigator', + complex_organization_attributes: [{ + organization: 'University', + sub_organization: 'Department', + purpose: 'Research' + }] + }] + }], + managing_organization_attributes: [{ + organization: 'Managing organization name', + sub_organization: 'BarBar', + purpose: 'Managing organization', + complex_identifier_attributes: [{ + identifier: '123456789mo', + scheme: 'Local' + }] + }], + title: 'Instrument title' + }] + } + end + + trait :with_complex_specimen_type do + complex_specimen_type_attributes { + [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + complex_identifier_attributes: [{ + identifier: 'chemical_composition/1234567', + scheme: 'identifier persistent', + label: 'Identifier - Persistent' + }], + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + complex_identifier_attributes: [{ + identifier: ['crystallographic_structure/123456'], + label: ['Local'] + }], + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567', + scheme: 'identifier persistent', + label: 'Identifier - Persistent' + }], + complex_material_type_attributes: [{ + description: 'material description', + material_type: 'some material type', + material_sub_type: 'some other material sub type', + complex_identifier_attributes: [{ + identifier: ['material/ewfqwefqwef'], + scheme: 'identifier persistent', + label: 'Identifier - Persistent' + }], + }], + complex_purchase_record_attributes: [{ + date: ['2018-02-14'], + complex_identifier_attributes: [{ + identifier: ['purchase_record/123456'], + scheme: 'identifier persistent', + label: ['Identifier - Persistent'] + }], + supplier_attributes: [{ + organization: 'Fooss', + sub_organization: 'Barss', + purpose: 'Supplier', + complex_identifier_attributes: [{ + identifier: 'supplier/123456789', + scheme: 'Local' + }] + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: 'manufacturer/123456789', + scheme: 'Local' + }] + }], + purchase_record_item: ['Has a purchase record item'], + title: 'Purchase record title' + }], + complex_shape_attributes: [{ + description: 'shape description', + complex_identifier_attributes: [{ + identifier: ['shape/123456'], + scheme: 'identifier persistent', + label: 'Identifier - Persistent' + }] + }], + complex_state_of_matter_attributes: [{ + description: 'state of matter description', + complex_identifier_attributes: [{ + identifier: ['state/123456'], + scheme: 'identifier persistent', + label: 'Identifier - Persistent' + }] + }], + complex_structural_feature_attributes: [{ + description: 'structural feature description', + category: 'structural feature category', + sub_category: 'structural feature sub category', + complex_identifier_attributes: [{ + identifier: ['structural_feature/123456'], + scheme: 'identifier persistent', + label: 'Identifier - Persistent' + }] + }], + title: 'Specimen 1' + }] + } + end + + trait :with_complex_relation do + complex_relation_attributes { + [{ + title: 'A relation label', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['info:hdl/4263537/400'], + scheme: 'identifier persistent' + }], + relationship: 'isNewVersionOf' + }] + } + end + + trait :with_complex_rights do + complex_rights_attributes { + [{ + date: '1978-10-28', + rights: 'http://creativecommons.org/publicdomain/zero/1.0/' + }] + } + end + + trait :with_complex_version do + complex_version_attributes { + [{ + date: '1978-10-28', + description: 'Creating the first version', + identifier: 'id1', + version: '1.0' + }] + } + end + end +end diff --git a/hyrax/spec/factories/fedora.rb b/hyrax/spec/factories/fedora.rb new file mode 100644 index 00000000..6e9919f7 --- /dev/null +++ b/hyrax/spec/factories/fedora.rb @@ -0,0 +1,24 @@ +FactoryBot.define do + + factory :access_control, class: Hydra::AccessControl do + #visibility Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE + #access_rights Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE + + skip_create + end + + factory :list_source, class: ActiveFedora::Aggregation::ListSource do + skip_create + end + + factory :relation, class: ActiveTriples::Relation do + skip_create + end + + trait :private do + visibility { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE } + end + + +end + diff --git a/hyrax/spec/factories/file_sets.rb b/hyrax/spec/factories/file_sets.rb new file mode 100644 index 00000000..0debbd1d --- /dev/null +++ b/hyrax/spec/factories/file_sets.rb @@ -0,0 +1,40 @@ +FactoryBot.define do + factory :file_set do + transient do + user { create(:user) } + content { nil } + end + after(:build) do |fs, evaluator| + fs.apply_depositor_metadata evaluator.user.user_key + end + + after(:create) do |file, evaluator| + Hydra::Works::UploadFileToFileSet.call(file, evaluator.content) if evaluator.content + end + + trait :open do + visibility { 'open' } + title { ["Open File Set"] } + end + + trait :authenticated do + visibility { 'authenticated' } + title { ["Authenticated File Set"] } + end + + trait :embargo do + visibility { 'embargo' } + title { ["Embargo File Set"] } + end + + trait :lease do + visibility { 'lease' } + title { ["Leased File Set"] } + end + + trait :restricted do + visibility { 'restricted' } + title { ["Resstricted File Set"] } + end + end +end diff --git a/hyrax/spec/factories/image.rb b/hyrax/spec/factories/image.rb new file mode 100644 index 00000000..9510b9fc --- /dev/null +++ b/hyrax/spec/factories/image.rb @@ -0,0 +1,90 @@ +FactoryBot.define do + + factory :image do + title { ["Image"] } + access_control + skip_create + override_new_record + end + + trait :open do + visibility { 'open' } + title { ["Open Image"] } + end + + trait :with_alternative_title do + alternative_title { 'Alternative-Title-123' } + end + + trait :with_subject do + subject { ['Subject-123'] } + end + + trait :with_publisher do + publisher { ['Publisher-123'] } + end + + trait :with_language do + language { ['Faroese'] } + end + + trait :with_keyword do + keyword { ['Keyword-123'] } + end + + trait :with_resource_type do + resource_type { ['Resource-Type-123'] } + end + + trait :with_rights_statement do + rights_statement { ['Rights-Statement-123'] } + end + + trait :with_complex_date do + complex_date_attributes { + [{ + date: '2019-05-28', + description: 'Published' + }] + } + end + + trait :with_complex_identifier do + complex_identifier_attributes { + [ + { identifier: '10.0.1111', scheme: 'http://dx.doi.org', label: 'DOI' }, + { identifier: '10.0.2222', scheme: 'HTTPS://DX.DOI.ORG', label: 'DOI' }, + { identifier: '3333', label: 'Local ID' } + ] + } + end + + trait :with_complex_person do + complex_person_attributes { + [{ + name: 'Complex-Person-123', + role: ['operator'] + }] + } + end + + trait :with_complex_rights do + complex_rights_attributes { + [{ + date: '1978-10-28', + rights: 'http://creativecommons.org/publicdomain/zero/1.0/' + }] + } + end + + trait :with_complex_version do + complex_version_attributes { + [{ + date: '1978-10-28', + description: 'Complex-Version-123', + identifier: 'id1', + version: '1.0' + }] + } + end +end diff --git a/hyrax/spec/factories/override_new_record.rb b/hyrax/spec/factories/override_new_record.rb new file mode 100644 index 00000000..0ecda395 --- /dev/null +++ b/hyrax/spec/factories/override_new_record.rb @@ -0,0 +1,11 @@ +FactoryBot.define do + trait :override_new_record do + after(:build) do |instance| + # we need to override the new_record? method; otherwise it will check with via the Fedora API and initiate an HTTP call + instance.define_singleton_method(:new_record?) do + true + end + end + end +end + diff --git a/hyrax/spec/factories/publication.rb b/hyrax/spec/factories/publication.rb new file mode 100644 index 00000000..972ecd57 --- /dev/null +++ b/hyrax/spec/factories/publication.rb @@ -0,0 +1,158 @@ +FactoryBot.define do + + factory :publication do + title { ["Publication"] } + access_control + skip_create + override_new_record + + trait :open do + visibility { 'open' } + title { ["Open Publication"] } + end + + trait :with_people do + complex_person_attributes { + [ + { + first_name: ['Foo'], + last_name: 'Bar', + role: "author" + }, { + name: 'Big Baz', + role: "editor" + }, { + name: 'Small Buz', + role: "author" + }, { + first_name: ['Moo'], + last_name: 'Milk', + name: 'Moo Milk', + role: "data depositor" + } + ] + } + end + + trait :with_alternative_title do + alternative_title { 'Alternative-Title-123' } + end + + trait :with_keyword do + keyword { ['Keyword-123'] } + end + + trait :with_subject do + subject { ['Subject-123'] } + end + + trait :with_language do + language { ['Faroese'] } + end + + trait :with_resource_type do + resource_type { ['Resource-Type-123'] } + end + + trait :with_source do + source { ['Source-123'] } + end + + trait :with_rights_statement do + rights_statement { ['Rights-Statement-123'] } + end + + trait :with_issue do + issue { 'Issue-123' } + end + + trait :with_table_of_contents do + table_of_contents { 'Table-of-Contents-123' } + end + + trait :with_number_of_pages do + total_number_of_pages { 'Number-of-Pages-123' } + end + + trait :with_complex_identifier do + complex_identifier_attributes { + [ + { identifier: '10.0.1111', scheme: 'http://dx.doi.org', label: 'DOI' }, + { identifier: '10.0.2222', scheme: 'HTTPS://DX.DOI.ORG', label: 'DOI' }, + { identifier: '3333', label: 'Local ID' } + ] + } + end + + trait :with_solr_document do + solr_document { {} } + end + + trait :with_complex_date do + complex_date_attributes { [{ date: '2019-05-28', description: 'Published' }] } + end + + trait :with_place do + place { '221B Baker Street Place' } + end + + trait :with_publisher do + publisher { ['Publisher-123'] } + end + + trait :with_complex_event do + complex_event_attributes { + [{ + title: 'Event-Title-123', + invitation_status: true, + place: 'New Scotland Yard', + start_date: '2018-12-25', + end_date: '2019-01-01' + }] + } + end + + trait :with_complex_source do + complex_source_attributes { + [{ + alternative_title: 'Sub title for journal', + complex_person_attributes: [{ + name: 'AR', + role: 'Editor' + }], + end_page: '12', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }], + issue: '34', + sequence_number: '1.2.2', + start_page: '4', + title: 'Test journal', + total_number_of_pages: '8', + volume: '3' + }] + } + end + + trait :with_complex_rights do + complex_rights_attributes { + [{ + date: '1980-10-10', + rights: 'http://creativecommons.org/publicdomain/zero/1.0/' + }] + } + end + + trait :with_complex_version do + complex_version_attributes { + [{ + date: '1990-12-12', + description: 'Creating the first version', + identifier: 'id1', + version: '1.0' + }] + } + end + end +end diff --git a/hyrax/spec/factories/roles.rb b/hyrax/spec/factories/roles.rb new file mode 100644 index 00000000..0d16fc94 --- /dev/null +++ b/hyrax/spec/factories/roles.rb @@ -0,0 +1,10 @@ +# Based on: https://github.com/samvera/hyrax/blob/master/spec/factories/users.rb +FactoryBot.define do + factory :role do + sequence(:name) { |n| "role-#{n}"} + + trait :admin do + name { 'admin' } + end + end +end diff --git a/hyrax/spec/factories/users.rb b/hyrax/spec/factories/users.rb new file mode 100644 index 00000000..bd06127e --- /dev/null +++ b/hyrax/spec/factories/users.rb @@ -0,0 +1,49 @@ +# Based on: https://github.com/samvera/hyrax/blob/master/spec/factories/users.rb +FactoryBot.define do + factory :user do + sequence(:email) { |n| "user#{n}@example.com" } + sequence(:username) { |n| "user#{n}" } + sequence(:display_name) { |n| "User #{n}"} + password { 'password' } + + transient do + # Allow for custom groups when a user is instantiated. + # @example create(:user, groups: 'avacado') + groups { [] } + end + + trait :mock_groups do + # TODO: Register the groups for the given user key such that we can remove the following from other specs: + # `allow(::User.group_service).to receive(:byname).and_return(user.user_key => ['admin'])`` + after(:build) do |user, evaluator| + # In case we have the instance but it has not been persisted + ::RSpec::Mocks.allow_message(user, :groups).and_return(Array.wrap(evaluator.groups)) + # Given that we are stubbing the class, we need to allow for the original to be called + ::RSpec::Mocks.allow_message(user.class.group_service, :fetch_groups).and_call_original + # We need to ensure that each instantiation of the admin user behaves as expected. + # This resolves the issue of both the created object being used as well as re-finding the created object. + ::RSpec::Mocks.allow_message(user.class.group_service, :fetch_groups).with(user: user).and_return(Array.wrap(evaluator.groups)) + end + end + + trait :guest do + guest { true } + end + + trait :admin do + roles { build_list :role, 1, :admin } + end + + trait :nims_researcher do + sequence(:display_name) { |n| "Researcher #{n}"} + guest { false } + employee_type_code { 'A' } + end + + trait :nims_other do + sequence(:display_name) { |n| "Non-Researcher #{n}"} + guest { false } + employee_type_code { 'T' } + end + end +end diff --git a/hyrax/spec/factories/works.rb b/hyrax/spec/factories/works.rb new file mode 100644 index 00000000..4a010a5c --- /dev/null +++ b/hyrax/spec/factories/works.rb @@ -0,0 +1,8 @@ +FactoryBot.define do + factory :work do + title { ["Work"] } + access_control + skip_create + override_new_record + end +end diff --git a/hyrax/spec/features/_README_FIRST.txt b/hyrax/spec/features/_README_FIRST.txt new file mode 100644 index 00000000..93c66c79 --- /dev/null +++ b/hyrax/spec/features/_README_FIRST.txt @@ -0,0 +1,10 @@ +Rather than create more rspec features in this folder (/spec/features), please instead consider writing your tests as +behaviour-driven cucumber tests (in /features). + +At a high level, cucumber tests are more readable than rspecs. This is particularly important when the feature to be +tested involves several different parts of the system. + +For a quick introduction to writing cucumber tests, see: +https://semaphoreci.com/community/tutorials/introduction-to-writing-acceptance-tests-with-cucumber + +See also the Create Dataset example feature in /features/create_dataset.feature diff --git a/hyrax/spec/features/contact_form_spec.rb b/hyrax/spec/features/contact_form_spec.rb new file mode 100644 index 00000000..fb3d51d4 --- /dev/null +++ b/hyrax/spec/features/contact_form_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' +include Warden::Test::Helpers + +# NOTE: If you generated more than one work, you have to set "js: true" +RSpec.feature 'Show Contact form', js: false do + context 'a logged in user' do + let(:user) { build(:user) } + + before do + login_as user + end + + scenario "should display contact form" do + visit '/contact' + expect(page).to have_field 'Your Name', with: user.display_name, readonly: true + expect(page).to have_field 'Your Email', with: user.email, readonly: true + end + end +end diff --git a/hyrax/spec/features/create_image_spec.rb b/hyrax/spec/features/create_image_spec.rb new file mode 100644 index 00000000..43f907fa --- /dev/null +++ b/hyrax/spec/features/create_image_spec.rb @@ -0,0 +1,70 @@ +# Generated via +# `rails generate hyrax:work Image` +require 'rails_helper' +include Warden::Test::Helpers + +# NOTE: If you generated more than one work, you have to set "js: true" +RSpec.feature 'Create a Image', js: false do + + # TODO: investigate how to run integration tests via capybara / cucumber + before { skip 'requires fedora/solr test infrastructure to run' } + + context 'a logged in user' do + let(:user) do + User.new({ email: 'test@example.com', username: 'user' }) { |u| u.save(validate: false) } + end + let(:admin_set_id) { AdminSet.find_or_create_default_admin_set_id } + let(:permission_template) { Hyrax::PermissionTemplate.find_or_create_by!(source_id: admin_set_id) } + let(:workflow) { Sipity::Workflow.create!(active: true, name: 'test-workflow', permission_template: permission_template) } + + before do + # Create a single action that can be taken + Sipity::WorkflowAction.create!(name: 'submit', workflow: workflow) + + # Grant the user access to deposit into the admin set. + Hyrax::PermissionTemplateAccess.create!( + permission_template_id: permission_template.id, + agent_type: 'user', + agent_id: user.user_key, + access: 'deposit' + ) + login_as user + end + + scenario do + visit '/dashboard' + click_link "Works" + click_link "Add new work" + + # If you generate more than one work uncomment these lines + # choose "payload_concern", option: "Image" + # click_button "Create work" + + expect(page).to have_content "Add New Image" + click_link "Files" # switch tab + expect(page).to have_content "Add files" + expect(page).to have_content "Add folder" + within('span#addfiles') do + attach_file("files[]", "#{Hyrax::Engine.root}/spec/fixtures/image.jp2", visible: false) + attach_file("files[]", "#{Hyrax::Engine.root}/spec/fixtures/jp2_fits.xml", visible: false) + end + click_link "Descriptions" # switch tab + fill_in('Title', with: 'My Test Work') + fill_in('Creator', with: 'Doe, Jane') + fill_in('Keyword', with: 'testing') + select('In Copyright', from: 'Rights statement') + + # With selenium and the chrome driver, focus remains on the + # select box. Click outside the box so the next line can't find + # its element + find('body').click + choose('image_visibility_open') + expect(page).to have_content('Please note, making something visible to the world (i.e. marking this as Public) may be viewed as publishing which could impact your ability to') + check('agreement') + + click_on('Save') + expect(page).to have_content('My Test Work') + expect(page).to have_content "Your files are being processed by Hyrax in the background." + end + end +end diff --git a/hyrax/spec/features/create_publication_spec.rb b/hyrax/spec/features/create_publication_spec.rb new file mode 100644 index 00000000..1768af1e --- /dev/null +++ b/hyrax/spec/features/create_publication_spec.rb @@ -0,0 +1,73 @@ +# Generated via +# `rails generate hyrax:work Publication` +require 'rails_helper' +include Warden::Test::Helpers + +# NOTE: If you generated more than one work, you have to set "js: true" +RSpec.feature 'Create a Publication', js: false do + + # TODO: investigate how to run integration tests via capybara / cucumber + before { skip 'requires fedora/solr test infrastructure to run' } + + context 'a logged in user' do + let(:user_attributes) do + { email: 'test@example.com' } + end + let(:user) do + User.new(user_attributes) { |u| u.save(validate: false) } + end + let(:admin_set_id) { AdminSet.find_or_create_default_admin_set_id } + let(:permission_template) { Hyrax::PermissionTemplate.find_or_create_by!(source_id: admin_set_id) } + let(:workflow) { Sipity::Workflow.create!(active: true, name: 'test-workflow', permission_template: permission_template) } + + before do + # Create a single action that can be taken + Sipity::WorkflowAction.create!(name: 'submit', workflow: workflow) + + # Grant the user access to deposit into the admin set. + Hyrax::PermissionTemplateAccess.create!( + permission_template_id: permission_template.id, + agent_type: 'user', + agent_id: user.user_key, + access: 'deposit' + ) + login_as user + end + + scenario do + visit '/dashboard' + click_link "Works" + click_link "Add new work" + + # If you generate more than one work uncomment these lines + # choose "payload_concern", option: "Publication" + # click_button "Create work" + + expect(page).to have_content "Add New Publication" + click_link "Files" # switch tab + expect(page).to have_content "Add files" + expect(page).to have_content "Add folder" + within('span#addfiles') do + attach_file("files[]", "#{Hyrax::Engine.root}/spec/fixtures/image.jp2", visible: false) + attach_file("files[]", "#{Hyrax::Engine.root}/spec/fixtures/jp2_fits.xml", visible: false) + end + click_link "Descriptions" # switch tab + fill_in('Title', with: 'My Test Work') + fill_in('Creator', with: 'Doe, Jane') + fill_in('Keyword', with: 'testing') + select('In Copyright', from: 'Rights statement') + + # With selenium and the chrome driver, focus remains on the + # select box. Click outside the box so the next line can't find + # its element + find('body').click + choose('publication_visibility_open') + expect(page).to have_content('Please note, making something visible to the world (i.e. marking this as Public) may be viewed as publishing which could impact your ability to') + check('agreement') + + click_on('Save') + expect(page).to have_content('My Test Work') + expect(page).to have_content "Your files are being processed by Hyrax in the background." + end + end +end diff --git a/hyrax/spec/features/create_work_spec.rb b/hyrax/spec/features/create_work_spec.rb index 0c595745..653c8d58 100644 --- a/hyrax/spec/features/create_work_spec.rb +++ b/hyrax/spec/features/create_work_spec.rb @@ -5,6 +5,10 @@ # NOTE: If you generated more than one work, you have to set "js: true" RSpec.feature 'Create a Work', js: false do + + # TODO: investigate how to run integration tests via capybara / cucumber + before { skip 'requires fedora/solr test infrastructure to run' } + context 'a logged in user' do let(:user_attributes) do { email: 'test@example.com' } diff --git a/hyrax/spec/features/oai_pmh_spec.rb b/hyrax/spec/features/oai_pmh_spec.rb new file mode 100644 index 00000000..7e35b140 --- /dev/null +++ b/hyrax/spec/features/oai_pmh_spec.rb @@ -0,0 +1,36 @@ +# From Samvera Hyku +require 'rails_helper' + +RSpec.describe "OAI PMH Support", type: :feature do + let(:work) { create(:dataset, :open) } + let(:identifier) { work.id } + + before { work } + + scenario 'oai interface with works present' do + skip 'Temporarily disable API behaviour, see https://github.com/antleaf/nims-mdr-development/issues/241' + + it 'lists metadata prefixess' do + visit oai_provider_catalog_path(verb: 'ListMetadataFormats') + expect(page).to have_content('oai_dc') + end + + it 'retrieves a list of records' do + visit oai_provider_catalog_path(verb: 'ListRecords', metadataPrefix: 'oai_dc') + expect(page).to have_content("#{ENV['OAI_RECORD_PREFIX']}:#{identifier}") + expect(page).to have_content(work.title.first) + end + + it 'retrieves a single record' do + visit oai_provider_catalog_path(verb: 'GetRecord', metadataPrefix: 'oai_dc', identifier: identifier) + expect(page).to have_content("#{ENV['OAI_RECORD_PREFIX']}:#{identifier}") + expect(page).to have_content(work.title.first) + end + + it 'retrieves a list of identifiers' do + visit oai_provider_catalog_path(verb: 'ListIdentifiers', metadataPrefix: 'oai_dc') + expect(page).to have_content("#{ENV['OAI_RECORD_PREFIX']}:#{identifier}") + expect(page).not_to have_content(work.title.first) + end + end +end diff --git a/hyrax/spec/fixtures/complete_dataset.rb b/hyrax/spec/fixtures/complete_dataset.rb new file mode 100644 index 00000000..5b6f0763 --- /dev/null +++ b/hyrax/spec/fixtures/complete_dataset.rb @@ -0,0 +1,102 @@ +dataset_attributes = { + title: ['test dataset 1234'], + description: ['description 1'], + keyword: ['keyword 1', 'keyword 2'], + language: ['language 1'], + publisher: ['publisher 1'], + complex_rights_attributes: [{ + date: '1978-10-28', + rights: 'CC0' + }], + rights_statement: ['rights_statement 1'], + source: ['Source 1'], + subject: ['subject 1'], + alternative_title: 'Alternative Title', + complex_date_attributes: [{ + date: '1978-10-28', + description: 'http://purl.org/dc/terms/issued', + }], + complex_identifier_attributes: [{ + identifier: '10.0.0132132', + scheme: 'http://dx.doi.org', + label: 'DOI' + }], + complex_person_attributes: [{ + name: 'Foo Bar', + affiliation: 'author affiliation', + role: 'Author', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }], + uri: 'http://localhost/person/1234567' + }], + complex_version_attributes: [{ + date: '2018-10-28', + description: 'Creating the first version', + identifier: 'id1', + version: '1.0' + }], + characterization_methods: 'charge distribution', + computational_methods: 'computational methods', + data_origin: ['informatics and data science'], + complex_instrument_attributes: [{ + alternative_title: 'An instrument title', + complex_date_attributes: [{ + date: ['2018-02-14'], + description: 'Processed' + }], + description: 'Instrument description', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['Local'] + }], + function_1: ['Has a function'], + function_2: ['Has two functions'], + manufacturer: 'Manufacturer name', + complex_person_attributes: [{ + name: ['Name of operator'], + role: ['Operator'] + }], + organization: 'Organisation', + title: 'Instrument title' + }], + origin_system_provenance: 'origin system provenance', + properties_addressed: ['chemical -- impurity concentration'], + complex_relation_attributes: [{ + title: 'A related item', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['local'] + }], + relationship: 'isSupplementTo' + }], + specimen_set: 'Specimen', + specimen_type_attributes: [{ + chemical_composition: 'chemical composition', + crystallographic_structure: 'crystallographic structure', + description: 'Description', + complex_identifier_attributes: [{ + identifier: '1234567' + }], + material_types: 'material types', + purchase_record_attributes: [{ + date: ['2018-02-14'], + identifier: ['123456'], + purchase_record_item: ['Has a purchase record item'], + title: 'Purchase record title' + }], + complex_relation_attributes: [{ + url: 'http://example.com/relation', + relationship: 'isPreviousVersionOf' + }], + structural_features: 'structural features', + title: 'Instrument 1' + }], + synthesis_and_processing: 'Synthesis and processing methods', + custom_property_attributes: [{ + question: 'Full name', + response: 'My full name is ...' + }] +} diff --git a/hyrax/spec/fixtures/csv/example.csv b/hyrax/spec/fixtures/csv/example.csv new file mode 100644 index 00000000..59232a80 --- /dev/null +++ b/hyrax/spec/fixtures/csv/example.csv @@ -0,0 +1,8 @@ +"Code","Study_participation","Census_usually_resident_population_count" +"1","Full-time study",1000911 +"2","Part-time study",149919 +"4","Not studying",3548922 +"7","Response not identifiable",0 +"9","Not stated",0 +"TotalStated","Total stated",4699755 +"Total","Total",4699755 \ No newline at end of file diff --git a/hyrax/spec/fixtures/xml/other.txt b/hyrax/spec/fixtures/xml/other.txt new file mode 100644 index 00000000..e470f636 --- /dev/null +++ b/hyrax/spec/fixtures/xml/other.txt @@ -0,0 +1 @@ +This file is mostly empty. diff --git a/hyrax/spec/fixtures/xml/test.xml b/hyrax/spec/fixtures/xml/test.xml new file mode 100755 index 00000000..e074332d --- /dev/null +++ b/hyrax/spec/fixtures/xml/test.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + 123456789unknown + + + + nims-internal + 00112233 + Test1, TEST1 + + + nims-internal + 00445566 + Test2, TEST2 + + + nims-internal + 00778899 + Test3, TEST3 + + + nims-internal + 09876543 + Test4, TEST4 + + + + descriptional + + NIMS + + + + project0012345* + + + 1234* + + Passing + true + + + + + 2018-12-30 + 2018-12-31 + + + experiments + + *** + + + + Public + + + + unknown + + + + + + + + local-identifier + 999999999 + + unknown + + + + + + work/specimen/unknown.zip + + + + + + + + + diff --git a/hyrax/spec/forms/hyrax/dataset_form_spec.rb b/hyrax/spec/forms/hyrax/dataset_form_spec.rb new file mode 100644 index 00000000..9c003ea7 --- /dev/null +++ b/hyrax/spec/forms/hyrax/dataset_form_spec.rb @@ -0,0 +1,56 @@ +require 'rails_helper' + +RSpec.describe Hyrax::DatasetForm do + it { expect(described_class).to be < Hyrax::Forms::WorkForm } + + describe 'instance methods' do + let(:model) { build(:dataset) } + let(:ability) { Ability.new(create(:user)) } + let(:controller) { nil } # doesn't require a value for these tests + let(:form) { described_class.new(model, ability, controller) } + + describe '#metadata_tab_terms' do + subject { form.metadata_tab_terms } + it { is_expected.to include(:supervisor_approval, :title, :alternative_title, :data_origin, :description, + :keyword, :specimen_set, :complex_person, :complex_identifier, :complex_date, + :complex_rights, :complex_version, :complex_relation, :custom_property) } + end + + describe '#method_tab_terms' do + subject { form.method_tab_terms } + it { is_expected.to include(:characterization_methods, :computational_methods, :properties_addressed, :synthesis_and_processing) } + end + + describe '#instrument_tab_terms' do + subject { form.instrument_tab_terms } + it { is_expected.to include(:complex_instrument) } + end + + describe '#specimen_tab_terms' do + subject { form.specimen_tab_terms } + it { is_expected.to include(:complex_specimen_type) } + end + end + + describe '#build_permitted_params' do + subject { described_class.build_permitted_params } + + it { is_expected.to include(:member_of_collection_ids, :find_child_work) } + + context 'permitted params' do + it do + expect(described_class).to receive(:permitted_date_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_identifier_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_instrument_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_person_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_organization_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_relation_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_rights_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_specimen_type_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_version_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_custom_property_params).at_least(:once).and_call_original + subject + end + end + end +end diff --git a/hyrax/spec/forms/hyrax/image_form_spec.rb b/hyrax/spec/forms/hyrax/image_form_spec.rb new file mode 100644 index 00000000..0eadc65d --- /dev/null +++ b/hyrax/spec/forms/hyrax/image_form_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + +RSpec.describe Hyrax::ImageForm do + it { expect(described_class).to be < Hyrax::Forms::WorkForm } + + describe '#build_permitted_params' do + subject { described_class.build_permitted_params } + + context 'permitted params' do + it do + expect(described_class).to receive(:permitted_date_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_identifier_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_person_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_rights_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_version_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_relation_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_custom_property_params).at_least(:once).and_call_original + subject + end + end + end + +end diff --git a/hyrax/spec/forms/hyrax/publication_form_spec.rb b/hyrax/spec/forms/hyrax/publication_form_spec.rb new file mode 100644 index 00000000..fa82da90 --- /dev/null +++ b/hyrax/spec/forms/hyrax/publication_form_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe Hyrax::PublicationForm do + it { expect(described_class).to be < Hyrax::Forms::WorkForm } + + describe '#build_permitted_params' do + subject { described_class.build_permitted_params } + + it { is_expected.to include(:member_of_collection_ids, :find_child_work) } + + context 'permitted params' do + it do + expect(described_class).to receive(:permitted_date_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_identifier_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_person_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_rights_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_version_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_event_params).at_least(:once).and_call_original + expect(described_class).to receive(:permitted_source_params).at_least(:once).and_call_original + subject + end + end + end +end diff --git a/hyrax/spec/forms/hyrax/work_form_spec.rb b/hyrax/spec/forms/hyrax/work_form_spec.rb index cf82942a..e944a34c 100644 --- a/hyrax/spec/forms/hyrax/work_form_spec.rb +++ b/hyrax/spec/forms/hyrax/work_form_spec.rb @@ -1,9 +1,5 @@ -# Generated via -# `rails generate hyrax:work Work` require 'rails_helper' RSpec.describe Hyrax::WorkForm do - it "has tests" do - skip "Add your tests here" - end + it { expect(described_class).to be < Hyrax::Forms::WorkForm } end diff --git a/hyrax/spec/helpers/application_helper_spec.rb b/hyrax/spec/helpers/application_helper_spec.rb new file mode 100644 index 00000000..9203df3d --- /dev/null +++ b/hyrax/spec/helpers/application_helper_spec.rb @@ -0,0 +1,12 @@ +require 'rails_helper' + +RSpec.describe ApplicationHelper, :type => :helper do + + it 'has no instance methods' do + expect(subject.public_instance_methods).to be_empty + end + + it 'has no singleton methods' do + expect(subject.singleton_methods).to be_empty + end +end diff --git a/hyrax/spec/helpers/hyrax/citations_behaviors/name_behavior_helper_spec.rb b/hyrax/spec/helpers/hyrax/citations_behaviors/name_behavior_helper_spec.rb new file mode 100644 index 00000000..77c2a0ea --- /dev/null +++ b/hyrax/spec/helpers/hyrax/citations_behaviors/name_behavior_helper_spec.rb @@ -0,0 +1,77 @@ +require 'rails_helper' + +RSpec.describe Hyrax::CitationsBehaviors::NameBehavior, :type => :helper do + let(:publication) { build(:publication, :with_people) } + let(:presenter) { Hyrax::WorkPresenter.new(SolrDocument.new(publication.to_solr), Ability.new(nil)) } + + describe '#author_list' do + subject { helper.author_list(presenter) } + it { is_expected.to match_array(['Foo Bar', 'Small Buz']) } + end + + describe '#all_authors' do + subject { helper.all_authors(presenter) } + it { is_expected.to match_array(['Foo Bar', 'Small Buz']) } + end + + describe '#given_name_first' do + context 'without a comma' do + subject { helper.given_name_first('First LAST') } + it { is_expected.to eql('First LAST') } + end + + context 'with a comma' do + subject { helper.given_name_first('LAST, First') } + it { is_expected.to eql('First LAST') } + end + end + + describe '#surname_first' do + context 'without a comma' do + subject { helper.surname_first('First LAST') } + it { is_expected.to eql('LAST, First') } + end + + context 'with a comma' do + subject { helper.surname_first('LAST, First') } + it { is_expected.to eql('LAST, First') } + end + + context 'without a surname' do + subject { helper.surname_first('Alice') } + it { is_expected.to eql('Alice') } + end + end + + describe '#abbreviate_name' do + context 'without a comma' do + subject { helper.abbreviate_name('First LAST') } + it { is_expected.to eql('LAST, F.') } + end + + context 'with a comma' do + subject { helper.abbreviate_name('LAST, First') } + it { is_expected.to eql('LAST, F.') } + end + end + + describe 'dataset' do + let(:dataset) { build(:dataset, :with_complex_author) } + let(:presenter) { Hyrax::WorkPresenter.new(SolrDocument.new(dataset.to_solr), Ability.new(nil)) } + + context '#all_authors contains an author' do + subject { helper.all_authors(presenter) } + it { is_expected.to match_array(['Anamika']) } + end + + context '#all_authors is empty' do + let(:dataset) { build(:dataset, :with_complex_person) } + subject { helper.all_authors(presenter) } + it { is_expected.to match_array([]) } + end + end + + it 'has no singleton methods' do + expect(subject.singleton_methods).to be_empty + end +end diff --git a/hyrax/spec/helpers/hyrax/citations_behaviors/publication_behavior_helper_spec.rb b/hyrax/spec/helpers/hyrax/citations_behaviors/publication_behavior_helper_spec.rb new file mode 100644 index 00000000..dc3df793 --- /dev/null +++ b/hyrax/spec/helpers/hyrax/citations_behaviors/publication_behavior_helper_spec.rb @@ -0,0 +1,63 @@ +require 'rails_helper' + +RSpec.describe Hyrax::CitationsBehaviors::PublicationBehavior, :type => :helper do + let(:presenter) { Hyrax::PublicationPresenter.new(SolrDocument.new(publication.to_solr), Ability.new(nil)) } + + describe '#setup_doi' do + let(:publication) { build(:publication, :with_complex_identifier) } + subject { helper.setup_doi(presenter) } + + context 'valid solr json' do + it { is_expected.to eql('10.0.1111. 10.0.2222') } + end + + context 'invalid solr json' do + before { allow(presenter).to receive(:complex_identifier) { 'some illegal solr json' } } + it { is_expected.to be_nil } + end + end + + describe '#setup_pub_date' do + let(:publication) { build(:publication, :with_complex_date) } + subject { helper.setup_pub_date(presenter) } + it { is_expected.to eql('0528') } + end + + describe '#setup_pub_place' do + context 'with publication' do + let(:publication) { build(:publication, :with_place) } + subject { helper.setup_pub_place(presenter) } + it { is_expected.to eql('221B Baker Street Place') } + end + context 'with dataset' do + let(:publication) { build(:dataset) } + subject { helper.setup_pub_place(presenter) } + it { is_expected.to eql('') } + end + end + + describe '#setup_pub_publisher' do + let(:publication) { build(:publication, :with_publisher) } + subject { helper.setup_pub_publisher(presenter) } + it { is_expected.to eql('Publisher-123') } + end + + describe '#setup_pub_info' do + let(:publication) { build(:publication, :with_complex_identifier, :with_complex_date, :with_place, :with_publisher) } + subject { helper.setup_pub_info(presenter, include_date) } + + context 'without date' do + let(:include_date) { false } + it { is_expected.to eql('221B Baker Street Place: Publisher-123. 10.0.1111. 10.0.2222') } + end + + context 'with date' do + let(:include_date) { true } + it { is_expected.to eql('221B Baker Street Place: Publisher-123, 0528. 10.0.1111. 10.0.2222') } + end + end + + it 'has no singleton methods' do + expect(subject.singleton_methods).to be_empty + end +end diff --git a/hyrax/spec/helpers/hyrax/iiif_helper_spec.rb b/hyrax/spec/helpers/hyrax/iiif_helper_spec.rb new file mode 100644 index 00000000..141a326c --- /dev/null +++ b/hyrax/spec/helpers/hyrax/iiif_helper_spec.rb @@ -0,0 +1,37 @@ +require 'rails_helper' + +RSpec.describe Hyrax::IiifHelper, :type => :helper do + let(:publication) { build(:publication) } + let(:mock_solr_doc) { instance_double(SolrDocument, hydra_model: publication) } # a bit of a hack to make the routing work in tests + let(:presenter) { Hyrax::WorkPresenter.new(mock_solr_doc, Ability.new(nil)) } + + describe '#iiif_viewer_display' do + subject { helper.iiif_viewer_display(presenter) } + it { is_expected.to start_with('
    ') } + it { is_expected.to include('') } + it { is_expected.to include('
    ') } + end + + describe '#iiif_viewer_display_partial' do + subject { helper.iiif_viewer_display_partial(presenter) } + it { is_expected.to eql('hyrax/base/iiif_viewers/universal_viewer')} + end + + describe '#universal_viewer_base_url' do + subject { helper.universal_viewer_base_url } + it { is_expected.to eql('http://test.host/uv/uv.html')} + end + + describe '#universal_viewer_config_url' do + subject { helper.universal_viewer_config_url } + it { is_expected.to eql('http://test.host/uv/uv-config.json')} + end + + it 'has no singleton methods' do + expect(subject.singleton_methods).to be_empty + end +end diff --git a/hyrax/spec/helpers/hyrax/nims_file_set_helper_spec.rb b/hyrax/spec/helpers/hyrax/nims_file_set_helper_spec.rb new file mode 100644 index 00000000..716c241a --- /dev/null +++ b/hyrax/spec/helpers/hyrax/nims_file_set_helper_spec.rb @@ -0,0 +1,52 @@ +require 'rails_helper' + +RSpec.describe Hyrax::NimsFileSetHelper, type: :helper do + let(:presenter) { Hyrax::NimsFileSetPresenter.new(solr_document, nil) } + let(:solr_document) { SolrDocument.new(mime_type_ssi: mime_type, id: '12345') } + + describe '#nims_media_display' do + let(:mime_type) { 'text/csv' } + subject { helper.nims_media_display(presenter) } + it { is_expected.to have_css('a', text: 'Preview') } + it { is_expected.to have_css('a', text: 'Download the file') } + end + + describe '#nims_media_display_partial' do + subject { helper.nims_media_display_partial(presenter) } + + context 'image' do + let(:mime_type) { 'image/tiff' } + it { is_expected.to eql 'hyrax/file_sets/media_display/image' } + end + + context 'video' do + let(:mime_type) { 'video/mpeg' } + it { is_expected.to eql 'hyrax/file_sets/media_display/video' } + end + + context 'audio' do + let(:mime_type) { 'audio/ogg' } + it { is_expected.to eql 'hyrax/file_sets/media_display/audio' } + end + + context 'pdf' do + let(:mime_type) { 'application/pdf' } + it { is_expected.to eql 'hyrax/file_sets/media_display/pdf' } + end + + context 'office_document' do + let(:mime_type) { 'application/vnd.ms-powerpoint' } + it { is_expected.to eql 'hyrax/file_sets/media_display/office_document' } + end + + context 'csv' do + let(:mime_type) { 'text/csv' } + it { is_expected.to eql 'hyrax/file_sets/media_display/csv' } + end + + context 'anything else' do + let(:mime_type) { 'foo/bar' } + it { is_expected.to eql 'hyrax/file_sets/media_display/default' } + end + end +end diff --git a/hyrax/spec/helpers/hyrax_helper_spec.rb b/hyrax/spec/helpers/hyrax_helper_spec.rb new file mode 100644 index 00000000..3a655d0e --- /dev/null +++ b/hyrax/spec/helpers/hyrax_helper_spec.rb @@ -0,0 +1,13 @@ +require 'rails_helper' + +RSpec.describe HyraxHelper, :type => :helper do + describe '#available_translations' do + it 'returns available translations' do + expect(helper.available_translations).to eql({"en"=>"English"}) + end + end + + it 'has no singleton methods' do + expect(subject.singleton_methods).to be_empty + end +end diff --git a/hyrax/spec/indexers/.keep b/hyrax/spec/indexers/.keep new file mode 100644 index 00000000..e69de29b diff --git a/hyrax/spec/indexers/dataset_indexer_spec.rb b/hyrax/spec/indexers/dataset_indexer_spec.rb new file mode 100644 index 00000000..1351a6ad --- /dev/null +++ b/hyrax/spec/indexers/dataset_indexer_spec.rb @@ -0,0 +1,961 @@ +require 'rails_helper' +require 'json' +RSpec.describe DatasetIndexer do + describe 'indexes an alternative title' do + before do + obj = build(:dataset, alternative_title: 'Another title') + @solr_document = obj.to_solr + end + it 'indexes as stored_searchable' do + expect(@solr_document['alternative_title_tesim']).to match_array(['Another title']) + end + end + + describe 'indexes a date active triple resource with all the attributes' do + before do + dates = [ + { + date: '1988-10-28', + description: 'http://bibframe.org/vocab/providerDate', + }, { + date: '2018-01-01' + } + ] + obj = build(:dataset, complex_date_attributes: dates) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_date_ssm') + expect(JSON.parse(@solr_document['complex_date_ssm'])).not_to be_empty + end + it 'indexes as dateable' do + expect(@solr_document['complex_date_dtsim']).to match_array( + ["1988-10-28T00:00:00Z", "2018-01-01T00:00:00Z"]) + end + it 'indexes year as facetable' do + expect(@solr_document['complex_year_sim']).to match_array( + ["1988", "2018"]) + end + it 'indexes each type as sortable' do + skip 'this cannot be multi-valued' + expect(@solr_document['complex_date_submitted_dtsi']).to match_array("1988-10-28T00:00:00Z") + end + it 'indexes each type as dateable' do + expect(@solr_document['complex_date_submitted_dtsim']).to match_array(["1988-10-28T00:00:00Z"]) + end + it 'indexes each type as displayable' do + expect(@solr_document['complex_date_submitted_ssm']).to match_array(["1988-10-28"]) + end + it 'indexes each year as facetable' do + expect(@solr_document['complex_year_submitted_sim']).to match_array(["1988"]) + end + end + + describe 'indexes an identifier active triple resource with all the attributes' do + before do + ids = [ + { + identifier: '0000-0000-0000-0000', + scheme: 'ORCID' + }, { + identifier: '1234', + scheme: 'identifier local' + }, { + identifier: '12345345234', + scheme: 'Orcid' + } + ] + obj = build(:dataset, complex_identifier_attributes: ids) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_identifier_ssm') + expect(JSON.parse(@solr_document['complex_identifier_ssm'])).not_to be_empty + end + it 'indexes as symbol' do + expect(@solr_document['complex_identifier_ssim']).to match_array(['0000-0000-0000-0000', '1234', '12345345234']) + end + it 'indexes each type as symbol' do + expect(@solr_document['complex_identifier_orcid_ssim']).to match_array(['0000-0000-0000-0000', '12345345234']) + expect(@solr_document['complex_identifier_identifier_local_ssim']).to match_array(['1234']) + end + end + + describe 'indexes the person active triple resource with all the attributes' do + before do + people = [ + { + first_name: ['Foo'], + last_name: 'Bar', + role: "author", + complex_identifier_attributes: [{ + identifier: 'abcdef', + scheme: 'Local' + }], + complex_affiliation_attributes: [{ + job_title: 'Researcher', + complex_organization_attributes: [{ + organization: 'Org 1', + sub_organization: 'Sub org 1' + }] + }] + }, { + name: 'Big Baz', + role: "editor", + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }], + complex_affiliation_attributes: [{ + job_title: 'Editor', + complex_organization_attributes: [{ + organization: 'Org 1', + sub_organization: 'Sub org 2' + }] + }] + }, { + name: 'Joe Blogg', + role: "author", + complex_identifier_attributes: [{ + identifier: 'qwerty', + scheme: 'Local' + }], + complex_affiliation_attributes: [{ + job_title: 'Professor', + complex_organization_attributes: [{ + organization: 'Org 1', + sub_organization: 'Sub org 1' + }] + }] + }, { + first_name: ['James'], + last_name: 'Bond', + name: 'James Bond', + role: "data depositor", + complex_identifier_attributes: [{ + identifier: 'asdfgh', + scheme: 'Local' + }], + complex_affiliation_attributes: [{ + job_title: 'Department administrator', + complex_organization_attributes: [{ + organization: 'Org 1', + sub_organization: 'Sub org 1' + }] + }] + } + ] + obj = build(:dataset, complex_person_attributes: people) + @solr_document = obj.to_solr + end + it 'indexes person as displayable' do + expect(@solr_document).to include('complex_person_ssm') + expect(JSON.parse(@solr_document['complex_person_ssm'])).not_to be_empty + end + it 'indexes name as facetable' do + expect(@solr_document['complex_person_sim']).to match_array(['Foo Bar', 'Big Baz', 'Joe Blogg', 'James Bond']) + end + it 'indexes name as stored searchable' do + expect(@solr_document['complex_person_tesim']).to match_array(['Foo Bar', 'Big Baz', 'Joe Blogg', 'James Bond']) + end + it 'index name by role as stored searchable' do + expect(@solr_document['complex_person_author_tesim']).to match_array(['Foo Bar', 'Joe Blogg']) + expect(@solr_document['complex_person_editor_tesim']).to match_array(['Big Baz']) + expect(@solr_document['complex_person_data_depositor_tesim']).to match_array(['James Bond']) + end + it 'index name by role as facetable' do + expect(@solr_document['complex_person_author_sim']).to match_array(['Foo Bar', 'Joe Blogg']) + expect(@solr_document['complex_person_editor_sim']).to match_array(['Big Baz']) + expect(@solr_document['complex_person_data_depositor_sim']).to match_array(['James Bond']) + end + it 'indexes identifier as symbol' do + expect(@solr_document['complex_person_identifier_ssim']).to match_array(['abcdef', '1234567', 'qwerty', 'asdfgh']) + end + it 'indexes affiliated organization as facetable' do + expect(@solr_document['complex_person_organization_sim']).to match_array(['Org 1']) + end + it 'indexes affiliated organization as stored searchable' do + expect(@solr_document['complex_person_organization_tesim']).to match_array(['Org 1']) + end + it 'indexes affiliated sub organization as facetable' do + expect(@solr_document['complex_person_sub_organization_sim']).to match_array(['Sub org 1', 'Sub org 2']) + end + it 'indexes affiliated sub organization as stored searchable' do + expect(@solr_document['complex_person_sub_organization_tesim']).to match_array(['Sub org 1', 'Sub org 2']) + end + end + + describe 'indexes the rights active triple resource with all the attributes' do + before do + rights = [ + { + date: '2018-02-14', + rights: 'CC-0', + }, + { + rights: 'Some other right' + } + ] + obj = build(:dataset, complex_rights_attributes: rights) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_rights_ssm') + expect(JSON.parse(@solr_document['complex_rights_ssm'])).not_to be_empty + end + it 'indexes as facetable' do + expect(@solr_document).to include('complex_rights_sim') + expect(@solr_document['complex_rights_sim']).to match_array(['CC-0', 'Some other right']) + end + end + + describe 'indexes the version active triple resource with all the attributes' do + before do + versions = [ + { + date: '2018-02-14', + description: 'First version', + identifier: 'some_id', + version: '1.0' + }, + { + version: '1.1' + } + ] + obj = build(:dataset, complex_version_attributes: versions) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_version_ssm') + expect(JSON.parse(@solr_document['complex_version_ssm'])).not_to be_empty + end + it 'indexes as symbol' do + expect(@solr_document['complex_version_ssim']).to match_array(['1.0', '1.1']) + end + end + + describe 'indexes the organization active triple resource with all the attributes' do + before do + organizations = [ + { + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'org purpose', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }] + }, + { + organization: 'Big', + sub_organization: 'Baz', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: '1234567890m', + scheme: 'Local' + }] + } + ] + obj = build(:dataset, complex_organization_attributes: organizations) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_organization_ssm') + expect(JSON.parse(@solr_document['complex_organization_ssm'])).not_to be_empty + end + it 'indexes organization as stored searchable' do + expect(@solr_document['complex_organization_tesim']).to match_array(['Foo', 'Big']) + end + it 'indexes organization as facetable' do + expect(@solr_document['complex_organization_sim']).to match_array(['Foo', 'Big']) + end + it 'indexes sub organization as stored searchable' do + expect(@solr_document['complex_sub_organization_tesim']).to match_array(['Bar', 'Baz']) + end + it 'indexes sub organization as facetable' do + expect(@solr_document['complex_sub_organization_sim']).to match_array(['Bar', 'Baz']) + end + end + + describe 'indexes characterization methods' do + before do + obj = build(:dataset, characterization_methods: ['Method D']) + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['characterization_methods_tesim']).to match_array(['Method D']) + end + end + + describe 'indexes computational methods' do + before do + obj = build(:dataset, computational_methods: ['Method D']) + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['computational_methods_tesim']).to match_array(['Method D']) + end + it 'indexes as facetable' do + expect(@solr_document['computational_methods_sim']).to match_array(['Method D']) + end + end + + describe 'indexes data origin' do + before do + obj = build(:dataset, data_origin: ['Origin A', 'Origin B']) + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['data_origin_tesim']).to match_array(['Origin A', 'Origin B']) + end + it 'indexes as facetable' do + expect(@solr_document['data_origin_sim']).to match_array(['Origin A', 'Origin B']) + end + end + + describe 'indexes an instrument active triple resource with all the attributes' do + before do + instruments = [{ + alternative_title: 'Another instrument title', + complex_date_attributes: [{ + date: ['2018-02-14'] + }], + description: 'Instrument description', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['Local'] + }], + instrument_function_attributes: [{ + column_number: 1, + category: 'some value', + sub_category: 'some other value', + description: 'Instrument function description' + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: '123456789m', + scheme: 'Local' + }] + }], + model_number: '123xfty', + complex_person_attributes: [{ + name: ['Name of operator'], + role: ['Operator'], + complex_affiliation_attributes: [{ + job_title: 'Technician', + complex_organization_attributes: [{ + organization: 'Org 1', + sub_organization: 'Sub org 1' + }] + }] + }], + managing_organization_attributes: [{ + organization: 'Managing organization name', + sub_organization: 'BarBar', + purpose: 'Managing organization', + complex_identifier_attributes: [{ + identifier: '123456789mo', + scheme: 'Local' + }] + }], + title: 'Instrument title' + },{ + alternative_title: 'Another instrument title 2', + complex_date_attributes: [{ + date: ['2019-02-14'], + description: ['Processed'] + }], + description: 'Instrument description 2', + complex_identifier_attributes: [{ + identifier: ['1234567890'], + label: ['Local'] + }], + instrument_function_attributes: [{ + column_number: 1, + category: 'some value 2', + sub_category: 'some other value 2', + description: 'Instrument function description 2' + }], + manufacturer_attributes: [{ + organization: 'Big', + sub_organization: 'Baz', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: '1234567890m', + scheme: 'Local' + }] + }], + model_number: 'ABC12E', + complex_person_attributes: [{ + name: ['Name of operator 2'], + role: ['Operator'], + complex_affiliation_attributes: [{ + job_title: 'Technician', + complex_organization_attributes: [{ + organization: 'Org 2', + sub_organization: 'Sub org 2' + }] + }] + }], + managing_organization_attributes: [{ + organization: 'BigBig', + sub_organization: 'BazBaz', + purpose: 'Managing organization', + complex_identifier_attributes: [{ + identifier: '1234567890mo', + scheme: 'Local' + }] + }], + title: 'Instrument title 2' + }] + obj = build(:dataset, complex_instrument_attributes: instruments) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_instrument_ssm') + expect(JSON.parse(@solr_document['complex_instrument_ssm'])).not_to be_empty + end + it 'indexes title as facetable to complex_instrument_sim' do + expect(@solr_document['complex_instrument_sim']).to match_array(['Instrument title', 'Instrument title 2']) + end + it 'indexes title as stored searchable' do + expect(@solr_document['instrument_title_tesim']).to match_array(['Instrument title', 'Instrument title 2']) + end + it 'indexes alternative title as stored searchable' do + expect(@solr_document['instrument_alternative_title_tesim']).to match_array(['Another instrument title', 'Another instrument title 2']) + end + it 'indexes date by type as dateable' do + expect(@solr_document['complex_date_processed_dtsim']).to match_array(["2018-02-14T00:00:00Z", "2019-02-14T00:00:00Z"]) + end + it 'indexes date by type as displayable' do + expect(@solr_document['complex_date_processed_ssm']).to match_array(["2018-02-14", "2019-02-14"]) + end + it 'indexes description as stored searchable' do + expect(@solr_document['instrument_description_tesim']).to match_array(['Instrument description', 'Instrument description 2']) + end + it 'indexes identifier as symbol' do + expect(@solr_document['instrument_identifier_ssim']).to match_array(['123456', '1234567890']) + end + it 'indexes manufacturer as stored searchable' do + expect(@solr_document['instrument_manufacturer_tesim']).to match_array(['Foo', 'Big']) + end + it 'indexes manufacturer as facetable' do + expect(@solr_document['instrument_manufacturer_sim']).to match_array(['Foo', 'Big']) + end + it 'indexes manufacturer sub organization as stored searchable' do + expect(@solr_document['instrument_manufacturer_sub_organization_tesim']).to match_array(['Bar', 'Baz']) + end + it 'indexes manufacturer sub organization as facetable' do + expect(@solr_document['instrument_manufacturer_sub_organization_sim']).to match_array(['Bar', 'Baz']) + end + it 'indexes model_number as stored_searchable' do + expect(@solr_document['instrument_model_number_tesim']).to match_array(['123xfty', 'ABC12E']) + end + it 'indexes model_number as facetable' do + expect(@solr_document['instrument_model_number_sim']).to match_array(['123xfty', 'ABC12E']) + end + it 'indexes person by role as stored searchable' do + expect(@solr_document['complex_person_operator_tesim']).to match_array(['Name of operator', 'Name of operator 2']) + end + it 'indexes person by role as facetable' do + expect(@solr_document['complex_person_operator_sim']).to match_array(['Name of operator', 'Name of operator 2']) + end + it 'indexes person affiliation by role as stored searchable' do + expect(@solr_document['complex_person_operator_organization_tesim']).to match_array(["Org 1", "Org 2"]) + end + it 'indexes person affiliation by role as facetable' do + expect(@solr_document['complex_person_operator_organization_sim']).to match_array(["Org 1", "Org 2"]) + end + it 'indexes managing organization as stored searchable' do + expect(@solr_document['instrument_managing_organization_tesim']).to match_array(['Managing organization name', 'BigBig']) + end + it 'indexes managing organization as facetable' do + expect(@solr_document['instrument_managing_organization_sim']).to match_array(['Managing organization name', 'BigBig']) + end + it 'indexes managing sub organization as stored searchable' do + expect(@solr_document['instrument_managing_sub_organization_tesim']).to match_array(['BarBar', 'BazBaz']) + end + it 'indexes managing sub organization as facetable' do + expect(@solr_document['instrument_managing_sub_organization_sim']).to match_array(['BarBar', 'BazBaz']) + end + end + + describe 'indexes origin system provenance' do + before do + obj = build(:dataset, origin_system_provenance: 'Origin A') + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['origin_system_provenance_tesim']).to match_array(['Origin A']) + end + end + + describe 'indexes part of' do + it 'indexes as stored searchable' do + skip "Not using this field. Raises RSolr::Error::ConnectionRefused when added to index." + obj = build(:dataset, part_of: ['Another record']) + @solr_document = obj.to_solr + expect(@solr_document['part_of_tesim']).to match_array(['Another record']) + end + end + + describe 'indexes properties_addressed' do + before do + obj = build(:dataset, properties_addressed: ['Property A', 'Yet another property B']) + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['properties_addressed_tesim']).to match_array(['Property A', 'Yet another property B']) + end + end + + describe 'indexes the relation active triple resource with all the attributes' do + before do + relationships = [ + { + title: 'A related item', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['local'] + }], + relationship: 'isPartOf' + }, { + title: 'A 2nd related item', + url: 'http://example.com/relation2', + relationship: 'isPartOf' + }, { + title: 'A 3rd relation item', + url: 'http://example.com/relation3', + relationship: 'isNewVersionOf' + } + ] + obj = build(:dataset, complex_relation_attributes: relationships) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_relation_ssm') + expect(JSON.parse(@solr_document['complex_relation_ssm'])).not_to be_empty + end + it 'indexes the title as stored searchable' do + expect(@solr_document['complex_relation_title_tesim']).to match_array( + ['A related item', 'A 2nd related item', 'A 3rd relation item']) + end + it 'indexes the relationship as facetable' do + expect(@solr_document['complex_relation_relationship_sim']).to match_array( + ['isPartOf', 'isPartOf', 'isNewVersionOf']) + end + it 'indexes the relation by relationship as stored searchable' do + expect(@solr_document['complex_relation_ispartof_tesim']).to match_array( + ['A related item', 'A 2nd related item']) + expect(@solr_document['complex_relation_isnewversionof_tesim']).to match_array( + ['A 3rd relation item']) + end + it 'indexes the relation by relationship as facetable' do + expect(@solr_document['complex_relation_ispartof_sim']).to match_array( + ['A related item', 'A 2nd related item']) + expect(@solr_document['complex_relation_isnewversionof_sim']).to match_array( + ['A 3rd relation item']) + end + end + + describe 'indexes specimen set' do + before do + obj = build(:dataset, specimen_set: 'specimen A') + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['specimen_set_tesim']).to match_array(['specimen A']) + end + end + + describe 'indexes specimen type with all the attributes' do + before do + specimen_types = [ + { + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + complex_identifier_attributes: [{ + identifier: 'chemical_composition/12345' + }], + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic structure 1', + complex_identifier_attributes: [{ + identifier: ['crystallographic_structure/12345'], + label: ['Local'] + }], + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/12345' + }], + complex_material_type_attributes: [{ + description: 'material description', + material_type: 'some material type', + material_sub_type: 'some other material sub type', + complex_identifier_attributes: [{ + identifier: ['material/12345'], + label: ['Local'] + }], + }], + complex_purchase_record_attributes: [{ + date: ['2018-02-14'], + complex_identifier_attributes: [{ + identifier: ['purchase_record/12345'], + label: ['Local'] + }], + supplier_attributes: [{ + organization: 'Fooss', + sub_organization: 'Barss', + purpose: 'Supplier', + complex_identifier_attributes: [{ + identifier: 'supplier/12345', + scheme: 'Local' + }] + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: 'manufacturer/12345', + scheme: 'Local' + }] + }], + purchase_record_item: ['Item 1'], + title: 'Purchase record title' + }], + complex_shape_attributes: [{ + description: 'shape description', + complex_identifier_attributes: [{ + identifier: ['shape/12345'], + label: ['Local'] + }] + }], + complex_state_of_matter_attributes: [{ + description: 'state of matter description', + complex_identifier_attributes: [{ + identifier: ['state/12345'], + label: ['Local'] + }] + }], + complex_structural_feature_attributes: [{ + description: 'structural feature description', + category: 'structural feature category', + sub_category: 'structural feature sub category', + complex_identifier_attributes: [{ + identifier: ['structural_feature/12345'], + label: ['Local'] + }] + }], + title: 'Specimen 1' + }, + { + complex_chemical_composition_attributes: [{ + description: 'chemical composition 2', + complex_identifier_attributes: [{ + identifier: 'chemical_composition/67890' + }], + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic structure 2', + complex_identifier_attributes: [{ + identifier: ['crystallographic_structure/67890'], + label: ['Local'] + }], + }], + description: 'Specimen description 2', + complex_identifier_attributes: [{ + identifier: 'specimen/67890' + }], + complex_material_type_attributes: [{ + description: 'material description 2', + material_type: 'some material type 2', + material_sub_type: 'some other material sub type 2', + complex_identifier_attributes: [{ + identifier: ['material/67890'], + label: ['Local'] + }], + }], + complex_purchase_record_attributes: [{ + date: ['2019-02-14'], + complex_identifier_attributes: [{ + identifier: ['purchase_record/67890'], + label: ['Local'] + }], + supplier_attributes: [{ + organization: 'Fooss', + sub_organization: 'Barss 2', + purpose: 'Supplier', + complex_identifier_attributes: [{ + identifier: 'supplier/67890', + scheme: 'Local' + }] + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar 2', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: 'manufacturer/67890', + scheme: 'Local' + }] + }], + purchase_record_item: ['Item 2'], + title: 'Purchase record title 2' + },{ + date: ['2019-03-14'], + complex_identifier_attributes: [{ + identifier: ['purchase_record/asdfg'], + label: ['Local'] + }], + supplier_attributes: [{ + organization: 'Fooss', + sub_organization: 'Barss', + purpose: 'Supplier', + complex_identifier_attributes: [{ + identifier: 'supplier/asdfg', + scheme: 'Local' + }] + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: 'manufacturer/12345', + scheme: 'Local' + }] + }], + purchase_record_item: ['Item 3'], + title: 'Purchase record title 3' + }], + complex_shape_attributes: [{ + description: 'shape description 2', + complex_identifier_attributes: [{ + identifier: ['shape/67890'], + label: ['Local'] + }] + }], + complex_state_of_matter_attributes: [{ + description: 'state of matter description 2', + complex_identifier_attributes: [{ + identifier: ['state/67890'], + label: ['Local'] + }] + }], + complex_structural_feature_attributes: [{ + description: 'structural feature description 2', + category: 'structural feature category 2', + sub_category: 'structural feature sub category', + complex_identifier_attributes: [{ + identifier: ['structural_feature/67890'], + label: ['Local'] + }] + }], + title: 'Specimen 2' + } + ] + obj = build(:dataset, complex_specimen_type_attributes: specimen_types) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_specimen_type_ssm') + expect(JSON.parse(@solr_document['complex_specimen_type_ssm'])).not_to be_empty + end + it 'indexes the title as stored_searchable' do + expect(@solr_document['complex_specimen_type_tesim']).to match_array(['Specimen 1', 'Specimen 2']) + end + it 'indexes description as stored_searchable' do + expect(@solr_document['complex_specimen_type_description_tesim']).to match_array( + ['Specimen description', 'Specimen description 2']) + end + it 'indexes identifier as symbol' do + expect(@solr_document['complex_specimen_type_identifier_ssim']).to match_array( + ['specimen/12345', 'specimen/67890']) + end + it 'indexes chemical_composition as stored_searchable' do + expect(@solr_document['complex_chemical_composition_tesim']).to match_array( + ['chemical composition 1', 'chemical composition 2']) + end + it 'indexes chemical_composition identifier as stored_searchable' do + expect(@solr_document['complex_chemical_composition_identifier_ssim']).to match_array( + ['chemical_composition/12345', 'chemical_composition/67890']) + end + it 'indexes crystallographic_structure as stored_searchable' do + expect(@solr_document['complex_crystallographic_structure_tesim']).to match_array( + ['crystallographic structure 1', 'crystallographic structure 2']) + end + it 'indexes crystallographic_structure identifier as stored_searchable' do + expect(@solr_document['complex_crystallographic_structure_identifier_ssim']).to match_array( + ['crystallographic_structure/12345', 'crystallographic_structure/67890']) + end + it 'indexes material type as stored_searchable' do + expect(@solr_document['complex_material_type_tesim']).to match_array( + ['some material type', 'some material type 2']) + end + it 'indexes material type as facetable' do + expect(@solr_document['complex_material_type_sim']).to match_array( + ['some material type', 'some material type 2']) + end + it 'indexes material type description as stored_searchable' do + expect(@solr_document['complex_material_type_description_tesim']).to match_array( + ['material description', 'material description 2']) + end + it 'indexes sub material type as stored_searchable' do + expect(@solr_document['complex_material_sub_type_tesim']).to match_array( + ['some other material sub type', 'some other material sub type 2']) + end + it 'indexes sub material type as facetable' do + expect(@solr_document['complex_material_sub_type_sim']).to match_array( + ['some other material sub type', 'some other material sub type 2']) + end + it 'indexes material type identifier as symbol' do + expect(@solr_document['complex_material_type_identifier_ssim']).to match_array( + ['material/12345', 'material/67890']) + end + it 'indexes purchase record item as stored_searchable' do + expect(@solr_document['complex_purchase_record_item_tesim']).to match_array( + ['Item 1', 'Item 2', 'Item 3']) + end + it 'indexes purchase record title as stored_searchable' do + expect(@solr_document['complex_purchase_record_title_tesim']).to match_array( + ['Purchase record title', 'Purchase record title 2', 'Purchase record title 3']) + end + it 'indexes purchase record title as facetable' do + expect(@solr_document['complex_purchase_record_title_sim']).to match_array( + ['Purchase record title', 'Purchase record title 2', 'Purchase record title 3']) + end + it 'indexes purchase record date as dateable' do + expect(@solr_document['complex_date_purchased_dtsim']).to match_array( + ["2018-02-14T00:00:00Z", "2019-02-14T00:00:00Z", "2019-03-14T00:00:00Z"]) + end + it 'indexes purchase record date as displayable' do + expect(@solr_document['complex_date_purchased_ssm']).to match_array( + ['2018-02-14', '2019-02-14', '2019-03-14']) + end + it 'indexes purchase record identifier as symbol' do + expect(@solr_document['complex_purchase_record_identifier_ssim']).to match_array( + ['purchase_record/12345', 'purchase_record/67890', 'purchase_record/asdfg']) + end + it 'indexes purchase record manufacturer as stored_searchable' do + expect(@solr_document['complex_purchase_record_manufacturer_tesim']).to match_array( + ['Foo', 'Foo', 'Foo']) + end + it 'indexes purchase record manufacturer as facetable' do + expect(@solr_document['complex_purchase_record_manufacturer_sim']).to match_array( + ['Foo', 'Foo', 'Foo']) + end + it 'indexes purchase record manufacturer sub_organization as stored_searchable' do + expect(@solr_document['complex_purchase_record_manufacturer_sub_organization_tesim']).to match_array( + ['Bar', 'Bar', 'Bar 2']) + end + it 'indexes purchase record manufacturer as facetable' do + expect(@solr_document['complex_purchase_record_manufacturer_sub_organization_sim']).to match_array( + ['Bar', 'Bar', 'Bar 2']) + end + it 'indexes purchase record supplier as stored_searchable' do + expect(@solr_document['complex_purchase_record_supplier_tesim']).to match_array( + ['Fooss', 'Fooss', 'Fooss']) + end + it 'indexes purchase record supplier as facetable' do + expect(@solr_document['complex_purchase_record_supplier_sim']).to match_array( + ['Fooss', 'Fooss', 'Fooss']) + end + it 'indexes purchase record supplier sub_organization as stored_searchable' do + expect(@solr_document['complex_purchase_record_supplier_sub_organization_tesim']).to match_array( + ['Barss', 'Barss', 'Barss 2']) + end + it 'indexes purchase record supplier as facetable' do + expect(@solr_document['complex_purchase_record_supplier_sub_organization_sim']).to match_array( + ['Barss', 'Barss', 'Barss 2']) + end + it 'indexes shape as stored_searchable' do + expect(@solr_document['complex_shape_tesim']).to match_array( + ['shape description', 'shape description 2']) + end + it 'indexes shape identifier as stored_searchable' do + expect(@solr_document['complex_shape_identifier_ssim']).to match_array( + ['shape/12345', 'shape/67890']) + end + it 'indexes state_of_matter as stored_searchable' do + expect(@solr_document['complex_state_of_matter_tesim']).to match_array( + ['state of matter description', 'state of matter description 2']) + end + it 'indexes state_of_matter identifier as stored_searchable' do + expect(@solr_document['complex_state_of_matter_identifier_ssim']).to match_array( + ['state/12345', 'state/67890']) + end + it 'indexes structural feature category as stored_searchable' do + expect(@solr_document['complex_structural_feature_category_tesim']).to match_array( + ['structural feature category', 'structural feature category 2']) + end + it 'indexes structural feature category as facetable' do + expect(@solr_document['complex_structural_feature_category_sim']).to match_array( + ['structural feature category', 'structural feature category 2']) + end + it 'indexes structural feature description as stored_searchable' do + expect(@solr_document['complex_structural_feature_description_tesim']).to match_array( + ['structural feature description', 'structural feature description 2']) + end + it 'indexes structural feature sub category as stored_searchable' do + expect(@solr_document['complex_structural_feature_sub_category_tesim']).to match_array( + ['structural feature sub category', 'structural feature sub category']) + end + it 'indexes structural feature sub category as facetable' do + expect(@solr_document['complex_structural_feature_sub_category_sim']).to match_array( + ['structural feature sub category', 'structural feature sub category']) + end + it 'indexes structural feature identifier as symbol' do + expect(@solr_document['complex_structural_feature_identifier_ssim']).to match_array( + ['structural_feature/12345', 'structural_feature/67890']) + end + end + + describe 'indexes synthesis and processing' do + before do + obj = build(:dataset, synthesis_and_processing: ['synthesis A']) + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['synthesis_and_processing_tesim']).to match_array(['synthesis A']) + end + it 'indexes as facetable' do + expect(@solr_document['synthesis_and_processing_sim']).to match_array(['synthesis A']) + end + end + + describe 'indexes a custom property (additional metadata) active triple resource with all the attributes' do + before do + custom_properties = [ + { + label: 'property 1', + description: 'Some description of the property' + }, { + label: 'Property 2', + description: 'Describing second property' + }, { + label: 'PROPERTY 2', + description: 'Describing second property again' + } + ] + obj = build(:dataset, custom_property_attributes: custom_properties) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('custom_property_ssm') + expect(JSON.parse(@solr_document['custom_property_ssm'])).not_to be_empty + end + it 'indexes each type as stored searchable' do + expect(@solr_document['custom_property_property_1_tesim']).to match_array( + ['Some description of the property']) + expect(@solr_document['custom_property_property_2_tesim']).to match_array( + ['Describing second property', 'Describing second property again']) + end + end + +end diff --git a/hyrax/spec/indexers/image_indexer_spec.rb b/hyrax/spec/indexers/image_indexer_spec.rb new file mode 100644 index 00000000..8ab75a73 --- /dev/null +++ b/hyrax/spec/indexers/image_indexer_spec.rb @@ -0,0 +1,192 @@ +require 'rails_helper' +require 'json' +RSpec.describe ImageIndexer do + describe 'indexes an alternative title' do + before do + obj = build(:image, alternative_title: 'Another title') + @solr_document = obj.to_solr + end + it 'indexes as stored_searchable' do + expect(@solr_document['alternative_title_tesim']).to match_array(['Another title']) + end + end + + describe 'indexes a date active triple resource with all the attributes' do + before do + dates = [ + { + date: '1988-10-28', + description: 'http://bibframe.org/vocab/providerDate', + }, { + date: '2018-01-01' + } + ] + obj = build(:image, complex_date_attributes: dates) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_date_ssm') + expect(JSON.parse(@solr_document['complex_date_ssm'])).not_to be_empty + end + it 'indexes as dateable' do + expect(@solr_document['complex_date_dtsim']).to match_array( + ["1988-10-28T00:00:00Z", "2018-01-01T00:00:00Z"]) + end + it 'indexes each type as sortable' do + skip 'this cannot be multi-valued' + expect(@solr_document['complex_date_submitted_dtsi']).to match_array("1988-10-28T00:00:00Z") + end + it 'indexes each type as dateable' do + expect(@solr_document['complex_date_submitted_dtsim']).to match_array(["1988-10-28T00:00:00Z"]) + end + it 'indexes each type as displayable' do + expect(@solr_document['complex_date_submitted_ssm']).to match_array(["1988-10-28"]) + end + end + + describe 'indexes an identifier active triple resource with all the attributes' do + before do + ids = [ + { + identifier: '0000-0000-0000-0000', + scheme: 'ORCID' + }, { + identifier: '1234', + scheme: 'identifier local' + }, { + identifier: '12345345234', + scheme: 'Orcid' + } + ] + obj = build(:image, complex_identifier_attributes: ids) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_identifier_ssm') + expect(JSON.parse(@solr_document['complex_identifier_ssm'])).not_to be_empty + end + it 'indexes as symbol' do + expect(@solr_document['complex_identifier_ssim']).to match_array(['0000-0000-0000-0000', '1234', '12345345234']) + end + it 'indexes each type as symbol' do + expect(@solr_document['complex_identifier_orcid_ssim']).to match_array(['0000-0000-0000-0000', '12345345234']) + expect(@solr_document['complex_identifier_identifier_local_ssim']).to match_array(['1234']) + end + end + + describe 'indexes the person active triple resource with all the attributes' do + before do + people = [ + { + first_name: ['Foo'], + last_name: 'Bar', + role: "author" + }, { + name: 'Big Baz', + role: "editor" + }, { + name: 'Small Buz', + role: "author" + }, { + first_name: ['Moo'], + last_name: 'Milk', + name: 'Moo Milk', + role: "data depositor" + } + ] + obj = build(:image, complex_person_attributes: people) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_person_ssm') + expect(JSON.parse(@solr_document['complex_person_ssm'])).not_to be_empty + end + it 'indexes as facetable' do + expect(@solr_document['complex_person_sim']).to match_array(['Foo Bar', 'Big Baz', 'Small Buz', 'Moo Milk']) + end + it 'indexes as stored searchable' do + expect(@solr_document['complex_person_tesim']).to match_array(['Foo Bar', 'Big Baz', 'Small Buz', 'Moo Milk']) + end + it 'index by role as stored searchable' do + expect(@solr_document['complex_person_author_tesim']).to match_array(['Foo Bar', 'Small Buz']) + expect(@solr_document['complex_person_editor_tesim']).to match_array(['Big Baz']) + expect(@solr_document['complex_person_data_depositor_tesim']).to match_array(['Moo Milk']) + end + it 'index by role as facetable' do + expect(@solr_document['complex_person_author_sim']).to match_array(['Foo Bar', 'Small Buz']) + expect(@solr_document['complex_person_editor_sim']).to match_array(['Big Baz']) + expect(@solr_document['complex_person_data_depositor_sim']).to match_array(['Moo Milk']) + end + end + + describe 'indexes the rights active triple resource with all the attributes' do + before do + rights = [ + { + date: '2018-02-14', + rights: 'CC-0', + }, + { + rights: 'Some other right' + } + ] + obj = build(:image, complex_rights_attributes: rights) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_rights_ssm') + expect(JSON.parse(@solr_document['complex_rights_ssm'])).not_to be_empty + end + it 'indexes as facetable' do + expect(@solr_document).to include('complex_rights_sim') + expect(@solr_document['complex_rights_sim']).to match_array(['CC-0', 'Some other right']) + end + end + + describe 'indexes the version active triple resource with all the attributes' do + before do + versions = [ + { + date: '2018-02-14', + description: 'First version', + identifier: 'some_id', + version: '1.0' + }, + { + version: '1.1' + } + ] + obj = build(:image, complex_version_attributes: versions) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_version_ssm') + expect(JSON.parse(@solr_document['complex_version_ssm'])).not_to be_empty + end + it 'indexes as symbol' do + expect(@solr_document['complex_version_ssim']).to match_array(['1.0', '1.1']) + end + end + + describe 'indexes part of' do + it 'indexes as stored searchable' do + skip "Not using this field. Raises RSolr::Error::ConnectionRefused when added to index." + obj = build(:image, part_of: ['Another record']) + @solr_document = obj.to_solr + expect(@solr_document['part_of_tesim']).to match_array(['Another record']) + end + end + + describe 'indexes status' do + before do + obj = build(:image, status: 'Status D') + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['status_tesim']).to eq ['Status D'] + end + it 'indexes as facetable' do + expect(@solr_document['status_sim']).to eq ['Status D'] + end + end +end diff --git a/hyrax/spec/indexers/publication_indexer_spec.rb b/hyrax/spec/indexers/publication_indexer_spec.rb new file mode 100644 index 00000000..5e523fb2 --- /dev/null +++ b/hyrax/spec/indexers/publication_indexer_spec.rb @@ -0,0 +1,313 @@ +require 'rails_helper' +require 'json' +RSpec.describe PublicationIndexer do + describe 'indexes an alternative title' do + before do + obj = build(:publication, alternative_title: 'Another title') + @solr_document = obj.to_solr + end + it 'indexes as stored_searchable' do + expect(@solr_document['alternative_title_tesim']).to match_array(['Another title']) + end + end + + describe 'indexes a date active triple resource with all the attributes' do + before do + dates = [ + { + date: '1988-10-28', + description: 'http://bibframe.org/vocab/providerDate', + }, { + date: '2018-01-01' + } + ] + @obj = build(:publication, complex_date_attributes: dates) + @solr_document = @obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_date_ssm') + expect(JSON.parse(@solr_document['complex_date_ssm'])).not_to be_empty + end + it 'indexes as dateable' do + expect(@solr_document['complex_date_dtsim']).to match_array( + ["1988-10-28T00:00:00Z", "2018-01-01T00:00:00Z"]) + end + it 'indexes each type as sortable' do + skip 'this cannot be multi-valued' + expect(@solr_document['complex_date_submitted_dtsi']).to match_array("1988-10-28T00:00:00Z") + end + it 'indexes each type as dateable' do + expect(@solr_document['complex_date_submitted_dtsim']).to match_array(["1988-10-28T00:00:00Z"]) + end + it 'indexes each type as displayable' do + expect(@solr_document['complex_date_submitted_ssm']).to match_array(["1988-10-28"]) + end + end + + describe 'indexes an identifier active triple resource with all the attributes' do + before do + ids = [ + { + identifier: '0000-0000-0000-0000', + scheme: 'ORCID' + }, { + identifier: '1234', + scheme: 'identifier local' + }, { + identifier: '12345345234', + scheme: 'Orcid' + } + ] + obj = build(:publication, complex_identifier_attributes: ids) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_identifier_ssm') + expect(JSON.parse(@solr_document['complex_identifier_ssm'])).not_to be_empty + end + it 'indexes as symbol' do + expect(@solr_document['complex_identifier_ssim']).to match_array(['0000-0000-0000-0000', '1234', '12345345234']) + end + it 'indexes each type as symbol' do + expect(@solr_document['complex_identifier_orcid_ssim']).to match_array(['0000-0000-0000-0000', '12345345234']) + expect(@solr_document['complex_identifier_identifier_local_ssim']).to match_array(['1234']) + end + end + + describe 'indexes the person active triple resource with all the attributes' do + before do + people = [ + { + first_name: ['Foo'], + last_name: 'Bar', + role: "author" + }, { + name: 'Big Baz', + role: "editor" + }, { + name: 'Small Buz', + role: "author" + }, { + first_name: ['Moo'], + last_name: 'Milk', + name: 'Moo Milk', + role: "data depositor" + } + ] + obj = build(:publication, complex_person_attributes: people) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_person_ssm') + expect(JSON.parse(@solr_document['complex_person_ssm'])).not_to be_empty + end + it 'indexes as facetable' do + expect(@solr_document['complex_person_sim']).to match_array(['Foo Bar', 'Big Baz', 'Small Buz', 'Moo Milk']) + end + it 'indexes as stored searchable' do + expect(@solr_document['complex_person_tesim']).to match_array(['Foo Bar', 'Big Baz', 'Small Buz', 'Moo Milk']) + end + it 'index by role as stored searchable' do + expect(@solr_document['complex_person_author_tesim']).to match_array(['Foo Bar', 'Small Buz']) + expect(@solr_document['complex_person_editor_tesim']).to match_array(['Big Baz']) + expect(@solr_document['complex_person_data_depositor_tesim']).to match_array(['Moo Milk']) + end + it 'index by role as facetable' do + expect(@solr_document['complex_person_author_sim']).to match_array(['Foo Bar', 'Small Buz']) + expect(@solr_document['complex_person_editor_sim']).to match_array(['Big Baz']) + expect(@solr_document['complex_person_data_depositor_sim']).to match_array(['Moo Milk']) + end + end + + describe 'indexes the rights active triple resource with all the attributes' do + before do + rights = [ + { + date: '2018-02-14', + rights: 'CC-0', + }, + { + rights: 'Some other right' + } + ] + obj = build(:publication, complex_rights_attributes: rights) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_rights_ssm') + expect(JSON.parse(@solr_document['complex_rights_ssm'])).not_to be_empty + end + it 'indexes as facetable' do + expect(@solr_document).to include('complex_rights_sim') + expect(@solr_document['complex_rights_sim']).to match_array(['CC-0', 'Some other right']) + end + end + + describe 'indexes the version active triple resource with all the attributes' do + before do + versions = [ + { + date: '2018-02-14', + description: 'First version', + identifier: 'some_id', + version: '1.0' + }, + { + version: '1.1' + } + ] + obj = build(:publication, complex_version_attributes: versions) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_version_ssm') + expect(JSON.parse(@solr_document['complex_version_ssm'])).not_to be_empty + end + it 'indexes as symbol' do + expect(@solr_document['complex_version_ssim']).to match_array(['1.0', '1.1']) + end + end + + describe 'indexes a complex event' do + before do + events = [ + { + end_date: '2019-01-01', + invitation_status: true, + place: '221B Baker Street', + start_date: '2018-12-25', + title: 'A Title' + }, { + end_date: '2019-02-02', + invitation_status: true, + place: 'number 32', + start_date: '2018-12-26', + title: '2nd Title' + }, { + end_date: '2019-03-03', + invitation_status: true, + place: 'number 64', + start_date: '2018-12-27', + title: '3rd event' + } + ] + obj = build(:publication, complex_event_attributes: events) + @solr_document = obj.to_solr + end + it 'indexes as displayable' do + expect(@solr_document).to include('complex_event_ssm') + expect(JSON.parse(@solr_document['complex_event_ssm'])).not_to be_empty + end + it 'indexes title as stored searchable' do + expect(@solr_document['complex_event_title_tesim']).to match_array(['A Title', '2nd Title', '3rd event']) + end + it 'indexes place as stored searchable' do + expect(@solr_document['complex_event_place_tesim']).to match_array(['221B Baker Street', 'number 32', 'number 64']) + end + end + + describe 'indexes issue' do + before do + obj = build(:publication, issue: 'Issue D') + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['issue_tesim']).to eq ['Issue D'] + end + end + + describe 'indexes place' do + before do + obj = build(:publication, place: '221B Baker street') + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['place_tesim']).to eq ['221B Baker street'] + end + it 'indexes as facetable' do + expect(@solr_document['place_sim']).to eq ['221B Baker street'] + end + end + + describe 'indexes table_of_contents' do + before do + obj = build(:publication, table_of_contents: 'Contents A') + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['table_of_contents_tesim']).to eq ['Contents A'] + end + end + + describe 'indexes total_number_of_pages' do + before do + obj = build(:publication, total_number_of_pages: '12') + @solr_document = obj.to_solr + end + it 'indexes as stored searchable' do + expect(@solr_document['total_number_of_pages_tesim']).to eq ['12'] + end + it 'indexes as sortable' do + expect(@solr_document['total_number_of_pages_si']).to eq '12' + end + end + + describe 'indexes a complex source' do + before do + source = [ + { + complex_person_attributes: [{ + name: 'AR', + role: 'Editor' + }], + end_page: '12', + issue: '34', + sequence_number: '1.2.2', + start_page: '4', + title: 'Test journal', + total_number_of_pages: '8', + volume: '3' + }, { + complex_person_attributes: [{ + name: 'RN', + role: 'Joint editor' + }], + end_page: '47', + issue: '2.3', + sequence_number: '2.3.7', + start_page: '41', + title: 'Journal 2', + total_number_of_pages: '7', + volume: '376' + } + ] + obj = build(:publication, complex_source_attributes: source) + @solr_document = obj.to_solr + end + it 'indexes source as displayable' do + expect(@solr_document).to include('complex_source_ssm') + expect(JSON.parse(@solr_document['complex_source_ssm'])).not_to be_empty + end + it 'indexes title as stored searchable' do + expect(@solr_document['complex_source_title_tesim']).to match_array(['Test journal', 'Journal 2']) + end + it 'indexes issue as stored searchable' do + expect(@solr_document['complex_source_issue_tesim']).to match_array(['34', '2.3']) + end + it 'indexes sequence_number as stored searchable' do + expect(@solr_document['complex_source_sequence_number_tesim']).to match_array(['1.2.2', '2.3.7']) + end + it 'indexes volume as stored searchable' do + expect(@solr_document['complex_source_volume_tesim']).to match_array(['3', '376']) + end + it 'index by person role as stored searchable' do + expect(@solr_document['complex_person_editor_tesim']).to match_array(['AR']) + expect(@solr_document['complex_person_joint_editor_tesim']).to match_array(['RN']) + end + it 'index by person role as facetable' do + expect(@solr_document['complex_person_editor_sim']).to match_array(['AR']) + expect(@solr_document['complex_person_joint_editor_sim']).to match_array(['RN']) + end + end + +end diff --git a/hyrax/spec/inputs/nested_affiliation_input_spec.rb b/hyrax/spec/inputs/nested_affiliation_input_spec.rb new file mode 100644 index 00000000..21a61514 --- /dev/null +++ b/hyrax/spec/inputs/nested_affiliation_input_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + +RSpec.describe NestedAffiliationInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_person) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_affiliation, nil, :multi_value, {}) } + let(:value) { dataset.complex_person.first.complex_affiliation.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_affiliation, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_affiliation_attributes_0_job_title', type: :text, with: 'Principal Investigator') + is_expected.to have_field('dataset[complex_affiliation_attributes][0]_complex_organization_attributes_0_organization', type: :text, with: 'University') + is_expected.to have_field('dataset[complex_affiliation_attributes][0]_complex_organization_attributes_0_sub_organization', type: :text, with: 'Department') + is_expected.to have_field('dataset[complex_affiliation_attributes][0]_complex_organization_attributes_0_purpose', type: :text, with: 'Research') + end +end diff --git a/hyrax/spec/inputs/nested_chemical_composition_input_spec.rb b/hyrax/spec/inputs/nested_chemical_composition_input_spec.rb new file mode 100644 index 00000000..a5ecdd42 --- /dev/null +++ b/hyrax/spec/inputs/nested_chemical_composition_input_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe NestedChemicalCompositionInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_chemical_composition) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_chemical_composition, nil, :multi_value, {}) } + let(:value) { dataset.complex_specimen_type.first.complex_chemical_composition.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_chemical_composition, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_chemical_composition_attributes_0_description', type: :text, with: 'chemical composition 1') + is_expected.to have_field('dataset[complex_chemical_composition_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'chemical_composition/1234567') + is_expected.to have_select('dataset[complex_chemical_composition_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + end +end diff --git a/hyrax/spec/inputs/nested_crystallographic_structure_input_spec.rb b/hyrax/spec/inputs/nested_crystallographic_structure_input_spec.rb new file mode 100644 index 00000000..bd1e3135 --- /dev/null +++ b/hyrax/spec/inputs/nested_crystallographic_structure_input_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe NestedCrystallographicStructureInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_crystallographic_structure) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_crystallographic_structure, nil, :multi_value, {}) } + let(:value) { dataset.complex_specimen_type.first.complex_crystallographic_structure.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_crystallographic_structure, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_crystallographic_structure_attributes_0_description', type: :text, with: 'crystallographic_structure 1') + is_expected.to have_field('dataset[complex_crystallographic_structure_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'crystallographic_structure/123456') + is_expected.to have_select('dataset[complex_crystallographic_structure_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + end +end diff --git a/hyrax/spec/inputs/nested_custom_property_input_spec.rb b/hyrax/spec/inputs/nested_custom_property_input_spec.rb new file mode 100644 index 00000000..4b72ce40 --- /dev/null +++ b/hyrax/spec/inputs/nested_custom_property_input_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe NestedCustomPropertyInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_custom_property) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :custom_property, nil, :multi_value, {}) } + let(:value) { dataset.custom_property.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :custom_property, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_custom_property_attributes_0_description', type: :text, with: 'Foo Bar') + is_expected.to have_field('dataset_custom_property_attributes_0_label', type: :text, with: 'Full name') + end +end diff --git a/hyrax/spec/inputs/nested_date_input_spec.rb b/hyrax/spec/inputs/nested_date_input_spec.rb new file mode 100644 index 00000000..a75a6ee7 --- /dev/null +++ b/hyrax/spec/inputs/nested_date_input_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe NestedDateInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_date) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_date, nil, :multi_value, {}) } + let(:value) { dataset.complex_date.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_date, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_date_attributes_0_date', type: :text, with: '1978-10-28') + is_expected.to have_select('dataset_complex_date_attributes_0_description', selected: 'Published') + end +end diff --git a/hyrax/spec/inputs/nested_event_input_spec.rb b/hyrax/spec/inputs/nested_event_input_spec.rb new file mode 100644 index 00000000..c75b61a1 --- /dev/null +++ b/hyrax/spec/inputs/nested_event_input_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe NestedEventInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:publication) { build(:publication, :with_complex_event) } + let(:object) { double(required?: true, model: publication) } + let(:builder) { SimpleForm::FormBuilder.new(:publication, object, view, {}) } + let(:input) { described_class.new(builder, :complex_event, nil, :multi_value, {}) } + let(:value) { publication.complex_event.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_event, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('publication_complex_event_attributes_0_title', type: :text, with: 'Event-Title-123') + is_expected.to have_field('publication_complex_event_attributes_0_place', type: :text, with: 'New Scotland Yard') + is_expected.to have_field('publication_complex_event_attributes_0_start_date', type: :text, with: '2018-12-25') + is_expected.to have_field('publication_complex_event_attributes_0_end_date', type: :text, with: '2019-01-01') + is_expected.to have_field('publication_complex_event_attributes_0_invitation_status', type: :text, with: 'true') + end +end diff --git a/hyrax/spec/inputs/nested_identifier_input_spec.rb b/hyrax/spec/inputs/nested_identifier_input_spec.rb new file mode 100644 index 00000000..7bac40e6 --- /dev/null +++ b/hyrax/spec/inputs/nested_identifier_input_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe NestedIdentifierInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_identifier) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_identifier, nil, :multi_value, {}) } + let(:value) { dataset.complex_identifier.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_identifier, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_identifier_attributes_0_identifier', type: :text, with: '10.0.1111') + is_expected.to have_select('dataset_complex_identifier_attributes_0_scheme', selected: 'DOI') + end +end diff --git a/hyrax/spec/inputs/nested_instrument_function_input_spec.rb b/hyrax/spec/inputs/nested_instrument_function_input_spec.rb new file mode 100644 index 00000000..06491a09 --- /dev/null +++ b/hyrax/spec/inputs/nested_instrument_function_input_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + +RSpec.describe NestedInstrumentFunctionInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_instrument) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :instrument_function, nil, :multi_value, {}) } + let(:value) { dataset.complex_instrument.first.instrument_function.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :instrument_function, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_instrument_function_attributes_0_column_number', type: :text, with: '1') + is_expected.to have_field('dataset_instrument_function_attributes_0_category', type: :text, with: 'some value') + is_expected.to have_field('dataset_instrument_function_attributes_0_sub_category', type: :text, with: 'some other value') + is_expected.to have_field('dataset_instrument_function_attributes_0_description', type: :text, with: 'Instrument function description') + end +end diff --git a/hyrax/spec/inputs/nested_instrument_input_spec.rb b/hyrax/spec/inputs/nested_instrument_input_spec.rb new file mode 100644 index 00000000..10762e8e --- /dev/null +++ b/hyrax/spec/inputs/nested_instrument_input_spec.rb @@ -0,0 +1,53 @@ +require 'rails_helper' + +RSpec.describe NestedInstrumentInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_instrument) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :instrument, nil, :multi_value, {}) } + let(:value) { dataset.complex_instrument.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :instrument, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_instrument_attributes_0_title', type: :text, with: 'Instrument title') + is_expected.to have_field('dataset_instrument_attributes_0_alternative_title', type: :text, with: 'An instrument title') + + is_expected.to have_select('dataset[instrument_attributes][0]_complex_date_attributes_0_description', selected: 'Published') + is_expected.to have_field('dataset[instrument_attributes][0]_complex_date_attributes_0_date', type: :text, with: '2018-02-14') + + is_expected.to have_field('dataset_instrument_attributes_0_description', type: :text, with: 'Instrument description') + + is_expected.to have_select('dataset[instrument_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[instrument_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'instrument/27213727') + + is_expected.to have_field('dataset[instrument_attributes][0]_instrument_function_attributes_0_column_number', type: :text, with: '1') + is_expected.to have_field('dataset[instrument_attributes][0]_instrument_function_attributes_0_category', type: :text, with: 'some value') + is_expected.to have_field('dataset[instrument_attributes][0]_instrument_function_attributes_0_sub_category', type: :text, with: 'some other value') + is_expected.to have_field('dataset[instrument_attributes][0]_instrument_function_attributes_0_description', type: :text, with: 'Instrument function description') + + is_expected.to have_field('dataset[instrument_attributes][0]_manufacturer_attributes_0_organization', type: :text, with: 'Foo') + is_expected.to have_field('dataset[instrument_attributes][0]_manufacturer_attributes_0_sub_organization', type: :text, with: 'Bar') + is_expected.to have_field('dataset[instrument_attributes][0]_manufacturer_attributes_0_purpose', type: :text, with: 'Manufacturer') + + is_expected.to have_field('dataset_instrument_attributes_0_model_number', type: :text, with: '123xfty') + + is_expected.to have_field('dataset[instrument_attributes][0]_complex_person_attributes_0_name', type: :text, with: 'Name of operator') + is_expected.to have_select('dataset[instrument_attributes][0]_complex_person_attributes_0_role', selected: 'operator/データ測定者・計算者') + is_expected.to have_select('dataset[instrument_attributes][0][complex_person_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Local') + is_expected.to have_field('dataset[instrument_attributes][0][complex_person_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: '123456789mo') + is_expected.to have_field('dataset[instrument_attributes][0][complex_person_attributes][0]_complex_affiliation_attributes_0_job_title', type: :text, with: 'Principal Investigator') + is_expected.to have_field('dataset[instrument_attributes][0][complex_person_attributes][0][complex_affiliation_attributes][0]_complex_organization_attributes_0_organization', type: :text, with: 'University') + is_expected.to have_field('dataset[instrument_attributes][0][complex_person_attributes][0][complex_affiliation_attributes][0]_complex_organization_attributes_0_sub_organization', type: :text, with: 'Department') + is_expected.to have_field('dataset[instrument_attributes][0][complex_person_attributes][0][complex_affiliation_attributes][0]_complex_organization_attributes_0_purpose', type: :text, with: 'Research') + + is_expected.to have_field('dataset[instrument_attributes][0]_managing_organization_attributes_0_organization', type: :text, with: 'Managing organization name') + is_expected.to have_field('dataset[instrument_attributes][0]_managing_organization_attributes_0_sub_organization', type: :text, with: 'BarBar') + is_expected.to have_field('dataset[instrument_attributes][0]_managing_organization_attributes_0_purpose', type: :text, with: 'Managing organization') + end +end diff --git a/hyrax/spec/inputs/nested_material_type_input_spec.rb b/hyrax/spec/inputs/nested_material_type_input_spec.rb new file mode 100644 index 00000000..cb24a55d --- /dev/null +++ b/hyrax/spec/inputs/nested_material_type_input_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe NestedMaterialTypeInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_specimen_type) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_material_type, nil, :multi_value, {}) } + let(:value) { dataset.complex_specimen_type.first.complex_material_type.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_material_type, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_material_type_attributes_0_material_type', type: :text, with: 'some material type') + is_expected.to have_field('dataset_complex_material_type_attributes_0_material_sub_type', type: :text, with: 'some other material sub type') + is_expected.to have_field('dataset_complex_material_type_attributes_0_description', type: :text, with: 'material description') + is_expected.to have_field('dataset_complex_material_type_attributes_0_material_type', type: :text, with: 'some material type') + + is_expected.to have_select('dataset[complex_material_type_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_material_type_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'material/ewfqwefqwef') + end +end diff --git a/hyrax/spec/inputs/nested_organization_input_spec.rb b/hyrax/spec/inputs/nested_organization_input_spec.rb new file mode 100644 index 00000000..05548c72 --- /dev/null +++ b/hyrax/spec/inputs/nested_organization_input_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe NestedOrganizationInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_person) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_organization, nil, :multi_value, {}) } + let(:value) { dataset.complex_person.first.complex_affiliation.first.complex_organization.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_organization, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_organization_attributes_0_organization', type: :text, with: 'University') + is_expected.to have_field('dataset_complex_organization_attributes_0_sub_organization', type: :text, with: 'Department') + is_expected.to have_field('dataset_complex_organization_attributes_0_purpose', type: :text, with: 'Research') + end +end diff --git a/hyrax/spec/inputs/nested_person_input_spec.rb b/hyrax/spec/inputs/nested_person_input_spec.rb new file mode 100644 index 00000000..5c556337 --- /dev/null +++ b/hyrax/spec/inputs/nested_person_input_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe NestedPersonInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_person) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_person, nil, :multi_value, {}) } + let(:value) { dataset.complex_person.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_person, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_person_attributes_0_name', type: :text, with: 'Anamika') + is_expected.to have_select('dataset_complex_person_attributes_0_role', selected: 'operator/データ測定者・計算者') + + is_expected.to have_select('dataset[complex_person_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Local') + is_expected.to have_field('dataset[complex_person_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: '123456') + + is_expected.to have_field('dataset[complex_person_attributes][0]_complex_affiliation_attributes_0_job_title', type: :text, with: 'Principal Investigator') + is_expected.to have_field('dataset[complex_person_attributes][0][complex_affiliation_attributes][0]_complex_organization_attributes_0_organization', type: :text, with: 'University') + is_expected.to have_field('dataset[complex_person_attributes][0][complex_affiliation_attributes][0]_complex_organization_attributes_0_sub_organization', type: :text, with: 'Department') + is_expected.to have_field('dataset[complex_person_attributes][0][complex_affiliation_attributes][0]_complex_organization_attributes_0_purpose', type: :text, with: 'Research') + end +end diff --git a/hyrax/spec/inputs/nested_purchase_record_input_spec.rb b/hyrax/spec/inputs/nested_purchase_record_input_spec.rb new file mode 100644 index 00000000..1408f329 --- /dev/null +++ b/hyrax/spec/inputs/nested_purchase_record_input_spec.rb @@ -0,0 +1,34 @@ +require 'rails_helper' + +RSpec.describe NestedPurchaseRecordInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_specimen_type) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_purchase_record, nil, :multi_value, {}) } + let(:value) { dataset.complex_specimen_type.first.complex_purchase_record.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_purchase_record, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_purchase_record_attributes_0_title', type: :text, with: 'Purchase record title') + is_expected.to have_field('dataset_complex_purchase_record_attributes_0_date', type: :text, with: '2018-02-14') + + is_expected.to have_select('dataset[complex_purchase_record_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_purchase_record_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'purchase_record/123456') + + is_expected.to have_field('dataset[complex_purchase_record_attributes][0]_supplier_attributes_0_organization', type: :text, with: 'Fooss') + is_expected.to have_field('dataset[complex_purchase_record_attributes][0]_supplier_attributes_0_sub_organization', type: :text, with: 'Barss') + is_expected.to have_field('dataset[complex_purchase_record_attributes][0]_supplier_attributes_0_purpose', type: :text, with: 'Supplier') + + is_expected.to have_field('dataset[complex_purchase_record_attributes][0]_manufacturer_attributes_0_organization', type: :text, with: 'Foo') + is_expected.to have_field('dataset[complex_purchase_record_attributes][0]_manufacturer_attributes_0_sub_organization', type: :text, with: 'Bar') + is_expected.to have_field('dataset[complex_purchase_record_attributes][0]_manufacturer_attributes_0_purpose', type: :text, with: 'Manufacturer') + + is_expected.to have_field('dataset_complex_purchase_record_attributes_0_purchase_record_item', type: :text, with: 'Has a purchase record item') + end +end diff --git a/hyrax/spec/inputs/nested_relation_input_spec.rb b/hyrax/spec/inputs/nested_relation_input_spec.rb new file mode 100644 index 00000000..37bb8f5a --- /dev/null +++ b/hyrax/spec/inputs/nested_relation_input_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe NestedRelationInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_relation) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_relation, nil, :multi_value, {}) } + let(:value) { dataset.complex_relation.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_relation, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_relation_attributes_0_title', type: :text, with: 'A relation label') + is_expected.to have_field('dataset_complex_relation_attributes_0_url', type: :text, with: 'http://example.com/relation') + is_expected.to have_select('dataset_complex_relation_attributes_0_relationship', selected: 'is new version of') + end +end diff --git a/hyrax/spec/inputs/nested_rights_input_spec.rb b/hyrax/spec/inputs/nested_rights_input_spec.rb new file mode 100644 index 00000000..76d031b3 --- /dev/null +++ b/hyrax/spec/inputs/nested_rights_input_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe NestedRightsInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_rights) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_rights, nil, :multi_value, {}) } + let(:value) { dataset.complex_rights.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_rights, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_select('dataset_complex_rights_attributes_0_rights', selected: 'Creative Commons CC0 1.0 Universal') + is_expected.to have_field('dataset_complex_rights_attributes_0_date', type: :text, with: '1978-10-28') + end +end diff --git a/hyrax/spec/inputs/nested_shape_input_spec.rb b/hyrax/spec/inputs/nested_shape_input_spec.rb new file mode 100644 index 00000000..30832f85 --- /dev/null +++ b/hyrax/spec/inputs/nested_shape_input_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe NestedShapeInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_specimen_type) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_shape, nil, :multi_value, {}) } + let(:value) { dataset.complex_specimen_type.first.complex_shape.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_shape, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_select('dataset[complex_shape_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_shape_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'shape/123456') + is_expected.to have_field('dataset_complex_shape_attributes_0_description', type: :text, with: 'shape description') + end +end diff --git a/hyrax/spec/inputs/nested_source_input_spec.rb b/hyrax/spec/inputs/nested_source_input_spec.rb new file mode 100644 index 00000000..1abc87a8 --- /dev/null +++ b/hyrax/spec/inputs/nested_source_input_spec.rb @@ -0,0 +1,27 @@ +require 'rails_helper' + +RSpec.describe NestedSourceInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:publication) { build(:publication, :with_complex_source) } + let(:object) { double(required?: true, model: publication) } + let(:builder) { SimpleForm::FormBuilder.new(:publication, object, view, {}) } + let(:input) { described_class.new(builder, :complex_source, nil, :multi_value, {}) } + let(:value) { publication.complex_source.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_source, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('publication_complex_source_attributes_0_title', type: :text, with: 'Test journal') + is_expected.to have_field('publication_complex_source_attributes_0_alternative_title', type: :text, with: 'Sub title for journal') + is_expected.to have_field('publication_complex_source_attributes_0_start_page', type: :text, with: '4') + is_expected.to have_field('publication_complex_source_attributes_0_end_page', type: :text, with: '12') + is_expected.to have_field('publication_complex_source_attributes_0_issue', type: :text, with: '34') + is_expected.to have_field('publication_complex_source_attributes_0_sequence_number', type: :text, with: '1.2.2') + is_expected.to have_field('publication_complex_source_attributes_0_total_number_of_pages', type: :text, with: '8') + is_expected.to have_field('publication_complex_source_attributes_0_volume', type: :text, with: '3') + end +end diff --git a/hyrax/spec/inputs/nested_specimen_type_input_spec.rb b/hyrax/spec/inputs/nested_specimen_type_input_spec.rb new file mode 100644 index 00000000..e64e00bb --- /dev/null +++ b/hyrax/spec/inputs/nested_specimen_type_input_spec.rb @@ -0,0 +1,66 @@ +require 'rails_helper' + +RSpec.describe NestedSpecimenTypeInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_specimen_type) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_specimen_type, nil, :multi_value, {}) } + let(:value) { dataset.complex_specimen_type.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_specimen_type, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_specimen_type_attributes_0_title', type: :text, with: 'Specimen 1') + + is_expected.to have_select('dataset[complex_specimen_type_attributes][0][complex_chemical_composition_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_chemical_composition_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'chemical_composition/1234567') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_chemical_composition_attributes_0_description', type: :text, with: 'chemical composition 1') + + is_expected.to have_select('dataset[complex_specimen_type_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_crystallographic_structure_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'crystallographic_structure/123456') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_crystallographic_structure_attributes_0_description', type: :text, with: 'crystallographic_structure 1') + + is_expected.to have_field('dataset_complex_specimen_type_attributes_0_description', type: :text, with: 'Specimen description') + + is_expected.to have_select('dataset[complex_specimen_type_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'specimen/1234567') + + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_material_type_attributes_0_material_type', type: :text, with: 'some material type') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_material_type_attributes_0_material_sub_type', type: :text, with: 'some other material sub type') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_material_type_attributes_0_description', type: :text, with: 'material description') + is_expected.to have_select('dataset[complex_specimen_type_attributes][0][complex_material_type_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_material_type_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'material/ewfqwefqwef') + + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_purchase_record_attributes_0_title', type: :text, with: 'Purchase record title') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_purchase_record_attributes_0_date', type: :text, with: '2018-02-14') + is_expected.to have_select('dataset[complex_specimen_type_attributes][0][complex_purchase_record_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_purchase_record_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'purchase_record/123456') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_purchase_record_attributes][0]_supplier_attributes_0_organization', type: :text, with: 'Fooss') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_purchase_record_attributes][0]_supplier_attributes_0_sub_organization', type: :text, with: 'Barss') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_purchase_record_attributes][0]_supplier_attributes_0_purpose', type: :text, with: 'Supplier') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_purchase_record_attributes][0]_manufacturer_attributes_0_organization', type: :text, with: 'Foo') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_purchase_record_attributes][0]_manufacturer_attributes_0_sub_organization', type: :text, with: 'Bar') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_purchase_record_attributes][0]_manufacturer_attributes_0_purpose', type: :text, with: 'Manufacturer') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_purchase_record_attributes_0_purchase_record_item', type: :text, with: 'Has a purchase record item') + + is_expected.to have_select('dataset[complex_specimen_type_attributes][0][complex_shape_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_shape_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'shape/123456') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_shape_attributes_0_description', type: :text, with: 'shape description') + + is_expected.to have_select('dataset[complex_specimen_type_attributes][0][complex_state_of_matter_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_state_of_matter_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'state/123456') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_state_of_matter_attributes_0_description', type: :text, with: 'state of matter description') + + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_structural_feature_attributes_0_category', type: :text, with: 'structural feature category') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_structural_feature_attributes_0_sub_category', type: :text, with: 'structural feature sub category') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0]_complex_structural_feature_attributes_0_description', type: :text, with: 'structural feature description') + is_expected.to have_select('dataset[complex_specimen_type_attributes][0][complex_structural_feature_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_specimen_type_attributes][0][complex_structural_feature_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'structural_feature/123456') + end +end diff --git a/hyrax/spec/inputs/nested_state_of_matter_input_spec.rb b/hyrax/spec/inputs/nested_state_of_matter_input_spec.rb new file mode 100644 index 00000000..83df44ad --- /dev/null +++ b/hyrax/spec/inputs/nested_state_of_matter_input_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe NestedStateOfMatterInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_specimen_type) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_state_of_matter, nil, :multi_value, {}) } + let(:value) { dataset.complex_specimen_type.first.complex_state_of_matter.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_state_of_matter, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_select('dataset[complex_state_of_matter_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_state_of_matter_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'state/123456') + is_expected.to have_field('dataset_complex_state_of_matter_attributes_0_description', type: :text, with: 'state of matter description') + end +end diff --git a/hyrax/spec/inputs/nested_structural_feature_input_spec.rb b/hyrax/spec/inputs/nested_structural_feature_input_spec.rb new file mode 100644 index 00000000..8a01919d --- /dev/null +++ b/hyrax/spec/inputs/nested_structural_feature_input_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe NestedStructuralFeatureInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_specimen_type) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_structural_feature, nil, :multi_value, {}) } + let(:value) { dataset.complex_specimen_type.first.complex_structural_feature.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_structural_feature, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_structural_feature_attributes_0_category', type: :text, with: 'structural feature category') + is_expected.to have_field('dataset_complex_structural_feature_attributes_0_sub_category', type: :text, with: 'structural feature sub category') + is_expected.to have_field('dataset_complex_structural_feature_attributes_0_description', type: :text, with: 'structural feature description') + is_expected.to have_select('dataset[complex_structural_feature_attributes][0]_complex_identifier_attributes_0_scheme', selected: 'Identifier - Persistent') + is_expected.to have_field('dataset[complex_structural_feature_attributes][0]_complex_identifier_attributes_0_identifier', type: :text, with: 'structural_feature/123456') + end +end diff --git a/hyrax/spec/inputs/nested_version_input_spec.rb b/hyrax/spec/inputs/nested_version_input_spec.rb new file mode 100644 index 00000000..bb028986 --- /dev/null +++ b/hyrax/spec/inputs/nested_version_input_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe NestedVersionInput, type: :input do + it { expect(described_class).to be < NestedAttributesInput } + + let(:dataset) { build(:dataset, :with_complex_version) } + let(:object) { double(required?: true, model: dataset) } + let(:builder) { SimpleForm::FormBuilder.new(:dataset, object, view, {}) } + let(:input) { described_class.new(builder, :complex_version, nil, :multi_value, {}) } + let(:value) { dataset.complex_version.first } + let(:index) { 0 } + let(:options) { {} } + let(:html) { input.send(:build_components, :complex_version, value, index, options) } + + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_field('dataset_complex_version_attributes_0_version', type: :text, with: '1.0') + is_expected.to have_field('dataset_complex_version_attributes_0_date', type: :text, with: '1978-10-28') + end +end diff --git a/hyrax/spec/jobs/application_job_spec.rb b/hyrax/spec/jobs/application_job_spec.rb new file mode 100644 index 00000000..2d83262f --- /dev/null +++ b/hyrax/spec/jobs/application_job_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ::ApplicationJob, :type => :job do + it { expect(described_class).to be < ActiveJob::Base } +end diff --git a/hyrax/spec/lib/vocabularies/escidoc_publication_spec.rb b/hyrax/spec/lib/vocabularies/escidoc_publication_spec.rb new file mode 100644 index 00000000..797e7cd7 --- /dev/null +++ b/hyrax/spec/lib/vocabularies/escidoc_publication_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' +require './lib/vocabularies/escidoc_publication' + +RSpec.describe RDF::Vocab::ESciDocPublication do + it { expect(described_class).to be < RDF::Vocabulary } + it { expect(subject.value).to start_with 'http://purl.org/escidoc/metadata/terms/0.1/' } +end diff --git a/hyrax/spec/lib/vocabularies/nims_rdp_spec.rb b/hyrax/spec/lib/vocabularies/nims_rdp_spec.rb new file mode 100644 index 00000000..8804a704 --- /dev/null +++ b/hyrax/spec/lib/vocabularies/nims_rdp_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' +require './lib/vocabularies/nims_rdp' + +RSpec.describe RDF::Vocab::NimsRdp do + it { expect(described_class).to be < RDF::Vocabulary } + it { expect(subject.value).to start_with 'http://www.nims.go.jp/vocabs/ngdr/' } +end diff --git a/hyrax/spec/lib/vocabularies/rioxx_terms_spec.rb b/hyrax/spec/lib/vocabularies/rioxx_terms_spec.rb new file mode 100644 index 00000000..b1c1e2c5 --- /dev/null +++ b/hyrax/spec/lib/vocabularies/rioxx_terms_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' +require './lib/vocabularies/rioxx_terms' + +RSpec.describe RDF::Vocab::RioxxTerms do + it { expect(described_class).to be < RDF::Vocabulary } + it { expect(subject.value).to start_with 'http://data2paper.org/vocabularies/rioxxterms#' } +end diff --git a/hyrax/spec/mailers/application_mailer_spec.rb b/hyrax/spec/mailers/application_mailer_spec.rb new file mode 100644 index 00000000..e76cbd9b --- /dev/null +++ b/hyrax/spec/mailers/application_mailer_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ::ApplicationMailer, :type => :mailer do + it { expect(described_class).to be < ActionMailer::Base } +end diff --git a/hyrax/spec/models/ability_spec.rb b/hyrax/spec/models/ability_spec.rb new file mode 100644 index 00000000..84e61eaf --- /dev/null +++ b/hyrax/spec/models/ability_spec.rb @@ -0,0 +1,275 @@ +require 'rails_helper' + +RSpec.describe Ability do + let(:ability) { Ability.new(user) } + + describe '#custom_permissions' do + let(:role_create) { ability.can?(:create, Role) } + let(:role_show) { ability.can?(:show, Role) } + let(:role_add_user) { ability.can?(:add_user, Role) } + let(:role_remove_user) { ability.can?(:remove_user, Role) } + let(:role_index) { ability.can?(:index, Role) } + let(:role_edit) { ability.can?(:edit, Role) } + let(:role_update) { ability.can?(:update, Role) } + let(:role_destroy) { ability.can?(:destroy, Role) } + + let(:create_dataset) { ability.can?(:create, Dataset) } + let(:create_image) { ability.can?(:create, Image) } + let(:create_publication) { ability.can?(:create, Publication) } + let(:create_work) { ability.can?(:create, Work) } + + context 'admin user' do + let(:user) { create(:user, :admin) } + it { expect(role_create).to be true } + it { expect(role_show).to be true } + it { expect(role_add_user).to be true } + it { expect(role_remove_user).to be true } + it { expect(role_index).to be true } + it { expect(role_edit).to be true } + it { expect(role_update).to be true } + it { expect(role_destroy).to be true } + it { expect(create_dataset).to be true } + it { expect(create_image).to be true } + it { expect(create_publication).to be true } + it { expect(create_work).to be true } + end + + context 'guest user' do + let(:user) { create(:user, :guest) } + it { expect(role_create).to be false } + it { expect(role_show).to be false } + it { expect(role_add_user).to be false } + it { expect(role_remove_user).to be false } + it { expect(role_index).to be false } + it { expect(role_edit).to be false } + it { expect(role_update).to be false } + it { expect(role_destroy).to be false } + it { expect(create_dataset).to be false } + it { expect(create_image).to be false } + it { expect(create_publication).to be false } + it { expect(create_work).to be false } + end + end + + describe '#create_content' do + let(:models) { [::Dataset, ::Image, ::Publication] } + + context 'unauthenticated user' do + let(:user) { build(:user, :guest) } + it 'cannot create content' do + models.each do |model| + expect(ability.can?(:create, model)).to be false + end + end + end + + context 'authenticated NIMS non-Researcher' do + let(:user) { build(:user, :nims_other) } + it 'cannot create content' do + models.each do |model| + expect(ability.can?(:create, model)).to be false + end + end + end + + context 'authenticated NIMS Researcher' do + let(:user) { build(:user, :nims_researcher) } + it 'can create content' do + models.each do |model| + expect(ability.can?(:create, model)).to be true + end + end + end + + context 'admin user' do + let(:user) { build(:user, :admin) } + it 'can create content' do + models.each do |model| + expect(ability.can?(:create, model)).to be true + end + end + end + end + + describe '#read_metadata' do + let(:read_abstract) { ability.can?(:read_abstract, model) } + let(:read_alternative_title) { ability.can?(:read_alternative_title, model) } + let(:read_creator) { ability.can?(:read_creator, model) } + let(:read_date) { ability.can?(:read_date, model) } + let(:read_event) { ability.can?(:read_event, model) } + let(:read_identifier) { ability.can?(:read_identifier, model) } + let(:read_issue) { ability.can?(:read_issue, model) } + let(:read_table_of_contents) { ability.can?(:read_table_of_contents, model) } + let(:read_keyword) { ability.can?(:read_keyword, model) } + let(:read_language) { ability.can?(:read_language, model) } + let(:read_location) { ability.can?(:read_location, model) } + let(:read_number_of_pages) { ability.can?(:read_number_of_pages, model) } + let(:read_organization) { ability.can?(:read_organization, model) } + let(:read_publisher) { ability.can?(:read_publisher, model) } + let(:read_related) { ability.can?(:read_related, model) } + let(:read_resource_type) { ability.can?(:read_resource_type, model) } + let(:read_rights) { ability.can?(:read_rights, model) } + let(:read_source) { ability.can?(:read_source, model) } + let(:read_subject) { ability.can?(:read_subject, model) } + let(:read_title) { ability.can?(:read_title, model) } + let(:read_version) { ability.can?(:read_version, model) } + + context 'unauthenticated user' do + let(:user) { build(:user, :guest) } + + context 'dataset' do + let(:model) { ::Dataset} + it { expect(read_abstract).to be false } + it { expect(read_alternative_title).to be true } + it { expect(read_creator).to be true } + it { expect(read_date).to be true } + it { expect(read_event).to be false } + it { expect(read_identifier).to be true } + it { expect(read_issue).to be false } + it { expect(read_table_of_contents).to be false } + it { expect(read_keyword).to be true } + it { expect(read_language).to be true } + it { expect(read_location).to be false } + it { expect(read_number_of_pages).to be false } + it { expect(read_organization).to be true } + it { expect(read_publisher).to be true } + it { expect(read_related).to be true } + it { expect(read_resource_type).to be true } + it { expect(read_rights).to be true } + it { expect(read_source).to be true } + it { expect(read_subject).to be true } + it { expect(read_title).to be true } + it { expect(read_version).to be true } + end + + context 'image' do + let(:model) { ::Image} + it { expect(read_abstract).to be false } + it { expect(read_alternative_title).to be true } + it { expect(read_creator).to be true } + it { expect(read_date).to be true } + it { expect(read_event).to be false } + it { expect(read_identifier).to be true } + it { expect(read_issue).to be false } + it { expect(read_table_of_contents).to be false } + it { expect(read_keyword).to be true } + it { expect(read_language).to be true } + it { expect(read_location).to be false } + it { expect(read_number_of_pages).to be false } + it { expect(read_organization).to be false } + it { expect(read_publisher).to be true } + it { expect(read_related).to be false } + it { expect(read_resource_type).to be true } + it { expect(read_rights).to be true } + it { expect(read_source).to be false } + it { expect(read_subject).to be true } + it { expect(read_title).to be true } + it { expect(read_version).to be true } + end + + context 'publication' do + let(:model) { ::Publication} + it { expect(read_abstract).to be false } + it { expect(read_alternative_title).to be true } + it { expect(read_creator).to be true } + it { expect(read_date).to be true } + it { expect(read_event).to be true } + it { expect(read_identifier).to be true } + it { expect(read_issue).to be true } + it { expect(read_table_of_contents).to be true } + it { expect(read_keyword).to be true } + it { expect(read_language).to be true } + it { expect(read_location).to be true } + it { expect(read_number_of_pages).to be true } + it { expect(read_organization).to be true } + it { expect(read_publisher).to be true } + it { expect(read_related).to be true } + it { expect(read_resource_type).to be true } + it { expect(read_rights).to be true } + it { expect(read_source).to be true } + it { expect(read_subject).to be true } + it { expect(read_title).to be true } + it { expect(read_version).to be true } + end + end + + context 'authenticated NIMS Researcher' do + let(:user) { build(:user, :nims_researcher) } + + context 'dataset' do + let(:model) { ::Dataset} + it { expect(read_abstract).to be true } + it { expect(read_alternative_title).to be true } + it { expect(read_creator).to be true } + it { expect(read_date).to be true } + it { expect(read_event).to be false } + it { expect(read_identifier).to be true } + it { expect(read_issue).to be false } + it { expect(read_table_of_contents).to be false } + it { expect(read_keyword).to be true } + it { expect(read_language).to be true } + it { expect(read_location).to be false } + it { expect(read_number_of_pages).to be false } + it { expect(read_organization).to be true } + it { expect(read_publisher).to be true } + it { expect(read_related).to be true } + it { expect(read_resource_type).to be true } + it { expect(read_rights).to be true } + it { expect(read_source).to be true } + it { expect(read_subject).to be true } + it { expect(read_title).to be true } + it { expect(read_version).to be true } + end + + context 'image' do + let(:model) { ::Image} + it { expect(read_abstract).to be true } + it { expect(read_alternative_title).to be true } + it { expect(read_creator).to be true } + it { expect(read_date).to be true } + it { expect(read_event).to be false } + it { expect(read_identifier).to be true } + it { expect(read_issue).to be false } + it { expect(read_table_of_contents).to be false } + it { expect(read_keyword).to be true } + it { expect(read_language).to be true } + it { expect(read_location).to be false } + it { expect(read_number_of_pages).to be false } + it { expect(read_organization).to be false } + it { expect(read_publisher).to be true } + it { expect(read_related).to be false } + it { expect(read_resource_type).to be true } + it { expect(read_rights).to be true } + it { expect(read_source).to be false } + it { expect(read_subject).to be true } + it { expect(read_title).to be true } + it { expect(read_version).to be true } + end + + context 'publication' do + let(:model) { ::Publication} + it { expect(read_abstract).to be true } + it { expect(read_alternative_title).to be true } + it { expect(read_creator).to be true } + it { expect(read_date).to be true } + it { expect(read_event).to be true } + it { expect(read_identifier).to be true } + it { expect(read_issue).to be true } + it { expect(read_table_of_contents).to be true } + it { expect(read_keyword).to be true } + it { expect(read_language).to be true } + it { expect(read_location).to be true } + it { expect(read_number_of_pages).to be true } + it { expect(read_organization).to be true } + it { expect(read_publisher).to be true } + it { expect(read_related).to be true } + it { expect(read_resource_type).to be true } + it { expect(read_rights).to be true } + it { expect(read_source).to be true } + it { expect(read_subject).to be true } + it { expect(read_title).to be true } + it { expect(read_version).to be true } + end + end + end +end diff --git a/hyrax/spec/models/application_record_spec.rb b/hyrax/spec/models/application_record_spec.rb new file mode 100644 index 00000000..1502f6ca --- /dev/null +++ b/hyrax/spec/models/application_record_spec.rb @@ -0,0 +1,6 @@ +require 'rails_helper' + +RSpec.describe ::ApplicationRecord do + subject { described_class.abstract_class } + it { is_expected.to be true } +end diff --git a/hyrax/spec/models/concerns/.keep b/hyrax/spec/models/concerns/.keep new file mode 100644 index 00000000..e69de29b diff --git a/hyrax/spec/models/concerns/common_methods_spec.rb b/hyrax/spec/models/concerns/common_methods_spec.rb new file mode 100644 index 00000000..657b7508 --- /dev/null +++ b/hyrax/spec/models/concerns/common_methods_spec.rb @@ -0,0 +1,37 @@ +require 'rails_helper' + +RSpec.describe CommonMethods do + let(:test_class) { Struct.new(:id, :parent) { include CommonMethods } } + + context 'new record' do + subject { test_class.new('#new', 'parent') } + + it 'is a new record' do + expect(subject.new_record?).to be true + end + + it 'is not persisted' do + expect(subject.persisted?).to be false + end + + it 'has a final_parent' do + expect(subject.final_parent).to eql 'parent' + end + end + + context 'existing record' do + subject { test_class.new('existing', 'parent') } + + it 'is not a new record' do + expect(subject.new_record?).to be false + end + + it 'is persisted' do + expect(subject.persisted?).to be true + end + + it 'has a final_parent' do + expect(subject.final_parent).to eql 'parent' + end + end +end diff --git a/hyrax/spec/models/concerns/complex_affiliation_spec.rb b/hyrax/spec/models/concerns/complex_affiliation_spec.rb new file mode 100644 index 00000000..6f13b784 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_affiliation_spec.rb @@ -0,0 +1,134 @@ +require 'rails_helper' + +RSpec.describe ComplexAffiliation do + before do + class ExampleWork < ActiveFedora::Base + property :complex_affiliation, predicate: ::RDF::Vocab::VMD.affiliation, + class_name:"ComplexAffiliation" + accepts_nested_attributes_for :complex_affiliation + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_affiliation_attributes: [{job_title: 'Professor'}]}) + .complex_affiliation + .first + .job_title + end + it { is_expected.to eq ['Professor'] } + end + + it 'creates an affiliation active triple resource with an id and all properties' do + @obj = ExampleWork.new + @obj.attributes = { + complex_affiliation_attributes: [{ + job_title: 'Tester', + complex_organization_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'org purpose', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }] + }] + }] + } + expect(@obj.complex_affiliation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_affiliation.first.job_title).to eq ['Tester'] + expect(@obj.complex_affiliation.first.complex_organization.first.organization).to eq ['Foo'] + expect(@obj.complex_affiliation.first.complex_organization.first.sub_organization).to eq ['Bar'] + expect(@obj.complex_affiliation.first.complex_organization.first.purpose).to eq ['org purpose'] + expect(@obj.complex_affiliation.first.complex_organization.first.complex_identifier.first.identifier).to eq ['1234567'] + expect(@obj.complex_affiliation.first.complex_organization.first.complex_identifier.first.scheme).to eq ['Local'] + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_affiliation_attributes: [{ + job_title: 'Tester', + complex_organization_attributes: [{ + organization: 'Foo' + }] + }] + } + expect(@obj.complex_affiliation.first.id).to include('#affiliation') + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_affiliation, reject_if: :affiliation_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates an affiliation active triple resource with job_title and organization' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_affiliation_attributes: [{ + job_title: 'Operator', + complex_organization_attributes: [{ + organization: 'Anamika' + }] + }] + } + expect(@obj.complex_affiliation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_affiliation.first.job_title).to eq ['Operator'] + expect(@obj.complex_affiliation.first.complex_organization.first.organization).to eq ['Anamika'] + expect(@obj.complex_affiliation.first.complex_organization.first.sub_organization).to be_empty + expect(@obj.complex_affiliation.first.complex_organization.first.purpose).to be_empty + expect(@obj.complex_affiliation.first.complex_organization.first.complex_identifier).to be_empty + end + + it 'rejects an affiliation active triple with no organization and only job_title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_affiliation_attributes: [{ + job_title: 'Operator' + }] + } + expect(@obj.complex_affiliation).to be_empty + end + + it 'rejects an affiliation active triple with organization and no job_title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_affiliation_attributes: [{ + complex_organization_attributes: [{ + organization: 'Anamika' + }] + }] + } + expect(@obj.complex_affiliation).to be_empty + end + + it 'rejects an affiliation active triple with organization defined with other properties' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_affiliation_attributes: [{ + job_title: 'Operator', + complex_organization_attributes: [{ + sub_organization: 'My unit' + }] + }] + } + expect(@obj.complex_affiliation).to be_empty + end + + end +end diff --git a/hyrax/spec/models/concerns/complex_chemical_composition_spec.rb b/hyrax/spec/models/concerns/complex_chemical_composition_spec.rb new file mode 100644 index 00000000..1de3383d --- /dev/null +++ b/hyrax/spec/models/concerns/complex_chemical_composition_spec.rb @@ -0,0 +1,121 @@ +require 'rails_helper' + +RSpec.describe ComplexChemicalComposition do + before do + class ExampleWork < ActiveFedora::Base + property :complex_chemical_composition, predicate: ::RDF::Vocab::NimsRdp['chemical-composition'], + class_name:"ComplexChemicalComposition" + accepts_nested_attributes_for :complex_chemical_composition + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_chemical_composition_attributes: [{ description: 'chemical_composition 1' }]}) + .complex_chemical_composition + .first + .description + end + it { is_expected.to eq ['chemical_composition 1'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_chemical_composition_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }], + description: 'chemical_composition 1' + }] + } + expect(@obj.complex_chemical_composition.first.id).to include('#chemical_composition') + end + + it 'creates an chemical_composition active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_chemical_composition_attributes: [{ + description: 'chemical_composition description', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['Local'] + }] + }] + } + expect(@obj.complex_chemical_composition.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_chemical_composition.first.description).to eq ['chemical_composition description'] + expect(@obj.complex_chemical_composition.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_chemical_composition.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_chemical_composition.first.complex_identifier.first.label).to eq ['Local'] + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_chemical_composition, reject_if: :identifier_description_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates an chemical_composition active triple resource with description and identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_chemical_composition_attributes: [{ + description: 'chemical composition 12', + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + } + expect(@obj.complex_chemical_composition.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_chemical_composition.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_chemical_composition.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_chemical_composition.first.description).to eq ['chemical composition 12'] + end + + it 'rejects an chemical_composition active triple with no description' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_chemical_composition_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + } + expect(@obj.complex_chemical_composition).to be_empty + end + + it 'rejects an chemical_composition active triple with no identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_chemical_composition_attributes: [{ + description: 'composition 1' + }] + } + expect(@obj.complex_chemical_composition).to be_empty + @obj2 = ExampleWork2.new + @obj2.attributes = { + complex_chemical_composition_attributes: [{ + description: 'chemical_composition description', + complex_identifier_attributes: [{ + label: ['Local'] + }] + }] + } + expect(@obj2.complex_chemical_composition).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_crystallographic_structure_spec.rb b/hyrax/spec/models/concerns/complex_crystallographic_structure_spec.rb new file mode 100644 index 00000000..cefef3f8 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_crystallographic_structure_spec.rb @@ -0,0 +1,121 @@ +require 'rails_helper' + +RSpec.describe ComplexCrystallographicStructure do + before do + class ExampleWork < ActiveFedora::Base + property :complex_crystallographic_structure, predicate: ::RDF::Vocab::NimsRdp['chemical-composition'], + class_name:"ComplexCrystallographicStructure" + accepts_nested_attributes_for :complex_crystallographic_structure + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_crystallographic_structure_attributes: [{ description: 'crystallographic_structure 1' }]}) + .complex_crystallographic_structure + .first + .description + end + it { is_expected.to eq ['crystallographic_structure 1'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_crystallographic_structure_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }], + description: 'crystallographic_structure 1' + }] + } + expect(@obj.complex_crystallographic_structure.first.id).to include('#crystallographic_structure') + end + + it 'creates an crystallographic structure active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure description', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['Local'] + }] + }] + } + expect(@obj.complex_crystallographic_structure.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_crystallographic_structure.first.description).to eq ['crystallographic_structure description'] + expect(@obj.complex_crystallographic_structure.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_crystallographic_structure.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_crystallographic_structure.first.complex_identifier.first.label).to eq ['Local'] + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_crystallographic_structure, reject_if: :identifier_description_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates an crystallographic structure active triple resource with description and identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_crystallographic_structure_attributes: [{ + description: 'chemical composition 12', + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + } + expect(@obj.complex_crystallographic_structure.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_crystallographic_structure.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_crystallographic_structure.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_crystallographic_structure.first.description).to eq ['chemical composition 12'] + end + + it 'rejects an crystallographic structure active triple with no description' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_crystallographic_structure_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + } + expect(@obj.complex_crystallographic_structure).to be_empty + end + + it 'rejects an crystallographic structure active triple with no identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_crystallographic_structure_attributes: [{ + description: 'composition 1' + }] + } + expect(@obj.complex_crystallographic_structure).to be_empty + @obj2 = ExampleWork2.new + @obj2.attributes = { + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure description', + complex_identifier_attributes: [{ + label: ['Local'] + }] + }] + } + expect(@obj2.complex_crystallographic_structure).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_date_spec.rb b/hyrax/spec/models/concerns/complex_date_spec.rb new file mode 100644 index 00000000..93882bb8 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_date_spec.rb @@ -0,0 +1,95 @@ +require 'rails_helper' + +RSpec.describe ComplexDate do + before do + class ExampleWork < ActiveFedora::Base + property :complex_date, predicate: ::RDF::Vocab::DC.date, + class_name:"ComplexDate" + accepts_nested_attributes_for :complex_date + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_date_attributes: [{date: '2018-01-02'}]}) + .complex_date + .first + .date + end + it { is_expected.to eq ['2018-01-02'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_date_attributes: [ + { + date: '1978-10-06' + } + ] + } + expect(@obj.complex_date.first.id).to include('#date') + end + + it 'creates a date active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_date_attributes: [ + { + date: '1978-10-28', + description: 'Some kind of a date', + } + ] + } + expect(@obj.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_date.first.date).to eq ['1978-10-28'] + expect(@obj.complex_date.first.description).to eq ['Some kind of a date'] + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_date, reject_if: :date_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a date active triple resource with just the date' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_date_attributes: [ + { + date: '1984-09-01' + } + ] + } + expect(@obj.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_date.first.date).to eq ['1984-09-01'] + expect(@obj.complex_date.first.description).to be_empty + end + + it 'rejects a date active triple with no date' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_date_attributes: [ + { + description: 'Local date' + } + ] + } + expect(@obj.complex_date).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_event_spec.rb b/hyrax/spec/models/concerns/complex_event_spec.rb new file mode 100644 index 00000000..d53511a5 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_event_spec.rb @@ -0,0 +1,148 @@ +require 'rails_helper' + +RSpec.describe ComplexEvent do + before do + class ExampleWork < ActiveFedora::Base + property :complex_event, predicate: ::RDF::Vocab::ESciDocPublication.Event, class_name:"ComplexEvent" + accepts_nested_attributes_for :complex_event + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_event_attributes: [{ title: 'Title 1' }]}) + .complex_event + .first + .title + end + it { is_expected.to eq ['Title 1'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_event_attributes: [ + { + title: "A Title" + } + ] + } + expect(@obj.complex_event.first.id).to include('#event') + end + + it 'creates an event active triple resource with an id and all properties' do + @obj = ExampleWork.new + @obj.attributes = { + complex_event_attributes: [ + { + end_date: '2019-01-01', + invitation_status: true, + place: '221B Baker Street', + start_date: '2018-12-25', + title: 'A Title' + } + ] + } + expect(@obj.complex_event.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_event.first.end_date).to eq ['2019-01-01'] + expect(@obj.complex_event.first.invitation_status).to eq [true] + expect(@obj.complex_event.first.place).to eq ['221B Baker Street'] + expect(@obj.complex_event.first.start_date).to eq ['2018-12-25'] + expect(@obj.complex_event.first.title).to eq ['A Title'] + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_event, reject_if: :event_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates an event active triple resource with just the title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_event_attributes: [ + { + title: 'Some Title' + } + ] + } + expect(@obj.complex_event.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_event.first.title).to eq ['Some Title'] + expect(@obj.complex_event.first.end_date).to be_empty + expect(@obj.complex_event.first.invitation_status).to be_empty + expect(@obj.complex_event.first.place).to be_empty + expect(@obj.complex_event.first.start_date).to be_empty + end + + it 'rejects an event active triple with no title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_event_attributes: [ + { + start_date: '1970-01-01', + identifier: 'id1', + end_date: '2018-01-01' + } + ] + } + expect(@obj.complex_event).to be_empty + end + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_event, reject_if: :event_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates an event active triple resource with just the title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_event_attributes: [ + { + title: 'Some Title' + } + ] + } + expect(@obj.complex_event.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_event.first.title).to eq ['Some Title'] + expect(@obj.complex_event.first.end_date).to be_empty + expect(@obj.complex_event.first.invitation_status).to be_empty + expect(@obj.complex_event.first.place).to be_empty + expect(@obj.complex_event.first.start_date).to be_empty + end + + it 'rejects an event active triple with no title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_event_attributes: [ + { + start_date: '1970-01-01', + identifier: 'id1', + end_date: '2018-01-01' + } + ] + } + expect(@obj.complex_event).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_history_spec.rb b/hyrax/spec/models/concerns/complex_history_spec.rb new file mode 100644 index 00000000..26d07200 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_history_spec.rb @@ -0,0 +1,192 @@ +require 'rails_helper' + +RSpec.describe ComplexHistory do + before do + class ExampleWork < ActiveFedora::Base + property :complex_history, predicate: ::RDF::Vocab::NimsRdp['history'], + class_name:"ComplexHistory" + accepts_nested_attributes_for :complex_history + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_history_attributes: [{ upstream: 'Upstream 1' }]}) + .complex_history + .first + .upstream + end + it { is_expected.to eq ['Upstream 1'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_history_attributes: [{ + complex_event_date_attributes: [{ + date: ['2018-01-28'], + description: 'Event', + }], + complex_operator_attributes: [{ + name: ['operator 1'], + role: ['Operator'] + }], + upstream: 'Some event before', + downstream: 'Some event after' + }] + } + expect(@obj.complex_history.first.id).to include('#history') + end + + it 'creates a history active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_history_attributes: [{ + complex_event_date_attributes: [{ + date: ['2018-01-28'], + description: 'Event', + }], + complex_operator_attributes: [{ + name: ['operator 1'], + role: ['Operator'] + }], + upstream: 'An upstream event', + downstream: 'A downstream event' + }] + } + expect(@obj.complex_history.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.upstream).to eq ['An upstream event'] + expect(@obj.complex_history.first.downstream).to eq ['A downstream event'] + expect(@obj.complex_history.first.complex_event_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_event_date.first.date).to eq ['2018-01-28'] + expect(@obj.complex_history.first.complex_event_date.first.description).to eq ['Event'] + expect(@obj.complex_history.first.complex_operator.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_operator.first.name).to eq ['operator 1'] + expect(@obj.complex_history.first.complex_operator.first.role).to eq ['Operator'] + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_history, reject_if: :history_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a history active triple resource with event date, operator name, upstream and downstream events' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_history_attributes: [{ + complex_event_date_attributes: [{ + date: ['2018-01-28'] + }], + complex_operator_attributes: [{ + name: ['operator 1'] + }], + upstream: 'An upstream event', + downstream: 'A downstream event' + }] + } + expect(@obj.complex_history.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_event_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_event_date.first.date).to eq ['2018-01-28'] + expect(@obj.complex_history.first.complex_event_date.first.description).to be_empty + expect(@obj.complex_history.first.complex_operator.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_operator.first.name).to eq ['operator 1'] + expect(@obj.complex_history.first.complex_operator.first.role).to be_empty + expect(@obj.complex_history.first.upstream).to eq ['An upstream event'] + expect(@obj.complex_history.first.downstream).to eq ['A downstream event'] + end + + it 'creates a history active triple resource with only event date' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_history_attributes: [{ + complex_event_date_attributes: [{ + date: ['2018-01-28'] + }] + }] + } + expect(@obj.complex_history.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_event_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_event_date.first.date).to eq ['2018-01-28'] + expect(@obj.complex_history.first.complex_event_date.first.description).to be_empty + expect(@obj.complex_history.first.complex_operator).to be_empty + expect(@obj.complex_history.first.upstream).to be_empty + expect(@obj.complex_history.first.downstream).to be_empty + end + + it 'creates a history active triple resource with only operator name' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_history_attributes: [{ + complex_operator_attributes: [{ + name: ['operator 1'] + }] + }] + } + expect(@obj.complex_history.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_event_date).to be_empty + expect(@obj.complex_history.first.complex_operator.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_operator.first.name).to eq ['operator 1'] + expect(@obj.complex_history.first.complex_operator.first.role).to be_empty + expect(@obj.complex_history.first.upstream).to be_empty + expect(@obj.complex_history.first.downstream).to be_empty + end + + it 'creates a history active triple resource with only upstream event' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_history_attributes: [{ + upstream: 'An upstream event' + }] + } + expect(@obj.complex_history.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_event_date).to be_empty + expect(@obj.complex_history.first.complex_operator).to be_empty + expect(@obj.complex_history.first.upstream).to eq ['An upstream event'] + expect(@obj.complex_history.first.downstream).to be_empty + end + + it 'creates a history active triple resource with only downstream event' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_history_attributes: [{ + downstream: 'A downstream event' + }] + } + expect(@obj.complex_history.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_history.first.complex_event_date).to be_empty + expect(@obj.complex_history.first.complex_operator).to be_empty + expect(@obj.complex_history.first.upstream).to be_empty + expect(@obj.complex_history.first.downstream).to eq ['A downstream event'] + end + + it 'rejects an history active triple with no data' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_history_attributes: [{ + complex_operator_attributes: [{ + name: '', + role: ['Operator'] + }], + downstream: nil + }] + } + expect(@obj.complex_history).to be_empty + end + + end +end diff --git a/hyrax/spec/models/concerns/complex_identifier_spec.rb b/hyrax/spec/models/concerns/complex_identifier_spec.rb new file mode 100644 index 00000000..be6af017 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_identifier_spec.rb @@ -0,0 +1,98 @@ +require 'rails_helper' + +RSpec.describe ComplexIdentifier do + before do + class ExampleWork < ActiveFedora::Base + property :complex_identifier, predicate: ::RDF::Vocab::MODS.identifierGroup, + class_name:"ComplexIdentifier" + accepts_nested_attributes_for :complex_identifier + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_identifier_attributes: [{ identifier: '0000-0000-0000-0000' }]}) + .complex_identifier + .first + .identifier + end + it { is_expected.to eq ['0000-0000-0000-0000'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_identifier_attributes: [ + { + identifier: '0000-0000-0000-0000' + } + ] + } + expect(@obj.complex_identifier.first.id).to include('#identifier') + end + + it 'creates an identifier active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_identifier_attributes: [ + { + identifier: '0000-0000-0000-0000', + scheme: 'uri_of_ORCID_scheme', + label: 'ORCID' + } + ] + } + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['0000-0000-0000-0000'] + expect(@obj.complex_identifier.first.scheme).to eq ['uri_of_ORCID_scheme'] + expect(@obj.complex_identifier.first.label).to eq ['ORCID'] + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_identifier, reject_if: :identifier_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates an identifier active triple resource with just the identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_identifier_attributes: [ + { + identifier: '1234' + } + ] + } + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['1234'] + expect(@obj.complex_identifier.first.label).to be_empty + expect(@obj.complex_identifier.first.scheme).to be_empty + end + + it 'rejects an identifier active triple with no ientifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_identifier_attributes: [ + { + label: 'Local' + } + ] + } + expect(@obj.complex_identifier).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_instrument_function_spec.rb b/hyrax/spec/models/concerns/complex_instrument_function_spec.rb new file mode 100644 index 00000000..24442e7e --- /dev/null +++ b/hyrax/spec/models/concerns/complex_instrument_function_spec.rb @@ -0,0 +1,139 @@ +require 'rails_helper' + +RSpec.describe ComplexInstrumentFunction do + before do + class ExampleWork < ActiveFedora::Base + property :complex_instrument_function, predicate: ::RDF::Vocab::NimsRdp["instrument-function"], + class_name:"ComplexInstrumentFunction" + accepts_nested_attributes_for :complex_instrument_function + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_instrument_function_attributes: [{ description: 'Instrument Function 1' }]}) + .complex_instrument_function + .first + .description + end + it { is_expected.to eq ['Instrument Function 1'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_instrument_function_attributes: [{ + column_number: 1, + category: 'some value', + sub_category: 'some other value', + description: 'Instrument function description' + }] + } + expect(@obj.complex_instrument_function.first.id).to include('#category_code') + end + + it 'creates a complex category active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_instrument_function_attributes: [{ + column_number: 1, + category: 'some value', + sub_category: 'some other value', + description: 'Instrument function description' + }] + } + expect(@obj.complex_instrument_function.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument_function.first.column_number).to eq [1] + expect(@obj.complex_instrument_function.first.category).to eq ['some value'] + expect(@obj.complex_instrument_function.first.sub_category).to eq ['some other value'] + expect(@obj.complex_instrument_function.first.description).to eq ['Instrument function description'] + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_instrument_function, reject_if: :all_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a category type active triple resource with just the column_number' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_instrument_function_attributes: [{ + column_number: 5 + }] + } + expect(@obj.complex_instrument_function.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument_function.first.column_number).to eq [5] + expect(@obj.complex_instrument_function.first.category).to be_empty + expect(@obj.complex_instrument_function.first.sub_category).to be_empty + expect(@obj.complex_instrument_function.first.description).to be_empty + end + + it 'creates a category type active triple resource with just the category' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_instrument_function_attributes: [{ + category: 'asdfg' + }] + } + expect(@obj.complex_instrument_function.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument_function.first.column_number).to be_empty + expect(@obj.complex_instrument_function.first.category).to eq ['asdfg'] + expect(@obj.complex_instrument_function.first.sub_category).to be_empty + expect(@obj.complex_instrument_function.first.description).to be_empty + end + + it 'creates a category type active triple resource with just the sub_category' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_instrument_function_attributes: [{ + sub_category: 'asdfg' + }] + } + expect(@obj.complex_instrument_function.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument_function.first.column_number).to be_empty + expect(@obj.complex_instrument_function.first.category).to be_empty + expect(@obj.complex_instrument_function.first.sub_category).to eq ['asdfg'] + expect(@obj.complex_instrument_function.first.description).to be_empty + end + + it 'creates a category type active triple resource with just the description' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_instrument_function_attributes: [{ + description: 'Instrument function description' + }] + } + expect(@obj.complex_instrument_function.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument_function.first.column_number).to be_empty + expect(@obj.complex_instrument_function.first.category).to be_empty + expect(@obj.complex_instrument_function.first.sub_category).to be_empty + expect(@obj.complex_instrument_function.first.description).to eq ['Instrument function description'] + end + + it 'rejects a category type active triple with no values' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_instrument_function_attributes: [{ + column_number: nil, + category: '' + }] + } + expect(@obj.complex_instrument_function).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_instrument_spec.rb b/hyrax/spec/models/concerns/complex_instrument_spec.rb new file mode 100644 index 00000000..0de03df0 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_instrument_spec.rb @@ -0,0 +1,252 @@ +require 'rails_helper' + +RSpec.describe ComplexInstrument do + before do + class ExampleWork < ActiveFedora::Base + property :complex_instrument, predicate: ::RDF::Vocab::NimsRdp['instrument'], class_name:"ComplexInstrument" + accepts_nested_attributes_for :complex_instrument + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_instrument_attributes: [{ title: 'Instrument 1' }]}) + .complex_instrument + .first + .title + end + it { is_expected.to eq ['Instrument 1'] } + end + + context 'accepts valid complex_instrument_attributes' do + subject do + ExampleWork + .new({ complex_instrument_attributes: complex_instrument_attributes }) + .complex_instrument + .first + end + + context 'with date, identifier, person and title' do + let(:complex_instrument_attributes) do + [{ + complex_date_attributes: [{ + date: ['2018-01-28'], + }], + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }], + complex_person_attributes: [{ + name: ['operator 1'], + role: ['Operator'] + }], + title: 'Instrument 1' + }] + end + + it 'has the correct uri' do + expect(subject.id).to include('#instrument') + end + end + + context 'with all the attributes' do + let(:complex_instrument_attributes) do + [{ + alternative_title: 'An instrument title', + complex_date_attributes: [{ + date: ['2018-02-14'] + }], + description: 'Instrument description', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['Local'] + }], + instrument_function_attributes: [{ + column_number: 1, + category: 'some value', + sub_category: 'some other value', + description: 'Instrument function description' + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: '123456789m', + scheme: 'Local' + }] + }], + model_number: '123xfty', + complex_person_attributes: [{ + name: ['Name of operator'], + role: ['Operator'] + }], + managing_organization_attributes: [{ + organization: 'Managing organization name', + sub_organization: 'BarBar', + purpose: 'Managing organization', + complex_identifier_attributes: [{ + identifier: '123456789mo', + scheme: 'Local' + }] + }], + title: 'Instrument title' + }] + end + it 'creates an instrument active triple resource with all the attributes' do + expect(subject).to be_kind_of ActiveTriples::Resource + expect(subject.alternative_title).to eq ['An instrument title'] + expect(subject.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_date.first.date).to eq ['2018-02-14'] + expect(subject.description).to eq ['Instrument description'] + expect(subject.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_identifier.first.identifier).to eq ['123456'] + expect(subject.complex_identifier.first.label).to eq ['Local'] + expect(subject.instrument_function.first).to be_kind_of ActiveTriples::Resource + expect(subject.instrument_function.first.column_number).to eq [1] + expect(subject.instrument_function.first.category).to eq ['some value'] + expect(subject.instrument_function.first.sub_category).to eq ['some other value'] + expect(subject.instrument_function.first.description).to eq ['Instrument function description'] + expect(subject.manufacturer.first).to be_kind_of ActiveTriples::Resource + expect(subject.manufacturer.first.organization).to eq ['Foo'] + expect(subject.manufacturer.first.sub_organization).to eq ['Bar'] + expect(subject.manufacturer.first.purpose).to eq ['Manufacturer'] + expect(subject.manufacturer.first.complex_identifier.first.identifier).to eq ['123456789m'] + expect(subject.manufacturer.first.complex_identifier.first.scheme).to eq ['Local'] + expect(subject.model_number).to eq ['123xfty'] + expect(subject.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_person.first.name).to eq ['Name of operator'] + expect(subject.complex_person.first.role).to eq ['Operator'] + expect(subject.managing_organization.first).to be_kind_of ActiveTriples::Resource + expect(subject.managing_organization.first.organization).to eq ['Managing organization name'] + expect(subject.managing_organization.first.sub_organization).to eq ['BarBar'] + expect(subject.managing_organization.first.purpose).to eq ['Managing organization'] + expect(subject.managing_organization.first.complex_identifier.first.identifier).to eq ['123456789mo'] + expect(subject.managing_organization.first.complex_identifier.first.scheme).to eq ['Local'] + expect(subject.title).to eq ['Instrument title'] + end + end + end + + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_instrument, reject_if: :instrument_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + context 'accepts valid complex_instrument_attributes' do + subject do + ExampleWork2 + .new({ complex_instrument_attributes: complex_instrument_attributes }) + .complex_instrument + .first + end + + context 'date, identifier and person' do + let(:complex_instrument_attributes) do + [{ + complex_date_attributes: [{ date: ['2018-01-28'] }], + complex_identifier_attributes: [{ identifier: ['ewfqwefqwef'] }], + complex_person_attributes: [{ + name: ['operator 1'], + role: ['Operator'] + }] + }] + end + it 'creates an instrument active triple resource with date, identifier and person' do + expect(subject).to be_kind_of ActiveTriples::Resource + expect(subject.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_date.first.date).to eq ['2018-01-28'] + expect(subject.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(subject.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_person.first.name).to eq ['operator 1'] + expect(subject.complex_person.first.role).to eq ['Operator'] + end + end + end + + context 'rejects invalid complex_instrument_attributes' do + subject do + ExampleWork2 + .new({ complex_instrument_attributes: complex_instrument_attributes }) + .complex_instrument + end + + context 'rejects blank attributes' do + let(:complex_instrument_attributes) { [] } + it { is_expected.to be_empty } + end + + context "temporarily disabling attribute tests" do + # These tests are temporarily disabled because the attributes they are testing against have been temporariy disabled + # 27/8/2019 - temporarily remove required fields (#162) + before { skip 'temporarily disable required fields (#162)' } + + context 'rejects an instrument active triple with no date' do + let(:complex_instrument_attributes) do + [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }], + complex_person_attributes: [{ + name: ['operator 1'], + role: ['Operator'] + }] + }] + end + + it { is_expected.to be_empty } + end + + context 'rejects an instrument active triple with no identifier' do + let(:complex_instrument_attributes) do + [{ + complex_date_attributes: [{ + date: ['2018-01-28'], + }], + complex_person_attributes: [{ + name: ['operator 1'], + role: ['Operator'] + }] + }] + end + it { is_expected.to be_empty } + end + + context 'rejects an instrument active triple with no person' do + let(:complex_instrument_attributes) do + [{ + complex_date_attributes: [{ + date: ['2018-01-28'], + }], + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + end + it { is_expected.to be_empty } + end + + context 'rejects an instrument active triple with no date, identifier and person' do + let(:complex_instrument_attributes) { [{ title: 'Instrument A' }] } + it { is_expected.to be_empty } + end + end + end + end +end diff --git a/hyrax/spec/models/concerns/complex_key_value_spec.rb b/hyrax/spec/models/concerns/complex_key_value_spec.rb new file mode 100644 index 00000000..8116d37f --- /dev/null +++ b/hyrax/spec/models/concerns/complex_key_value_spec.rb @@ -0,0 +1,94 @@ +require 'rails_helper' + +RSpec.describe ComplexKeyValue do + before do + class ExampleWork < ActiveFedora::Base + property :custom_property, predicate: ::RDF::Vocab::NimsRdp['custom-properties'], + class_name:"ComplexKeyValue" + accepts_nested_attributes_for :custom_property + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ custom_property_attributes: [{ label: 'Label 1' }]}) + .custom_property + .first + .label + end + it { is_expected.to eq ['Label 1'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + custom_property_attributes: [ + { + label: 'Full name', + description: 'My full name is ...' + } + ] + } + expect(@obj.custom_property.first.id).to include('#key_value') + end + + it 'creates a custom property (additional metadata) active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + custom_property_attributes: [ + { + label: 'Full name', + description: 'My full name is ...' + } + ] + } + expect(@obj.custom_property.first).to be_kind_of ActiveTriples::Resource + expect(@obj.custom_property.first.label).to eq ['Full name'] + expect(@obj.custom_property.first.description).to eq ['My full name is ...'] + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :custom_property, reject_if: :key_value_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'rejects a custom property (additional metadata) active triple with no label' do + @obj = ExampleWork2.new + @obj.attributes = { + custom_property_attributes: [ + { + description: 'Local date' + } + ] + } + expect(@obj.custom_property).to be_empty + end + + it 'rejects a custom property (additional metadata) active triple with no description' do + @obj = ExampleWork2.new + @obj.attributes = { + custom_property_attributes: [ + { + label: 'Local date' + } + ] + } + expect(@obj.custom_property).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_material_type_spec.rb b/hyrax/spec/models/concerns/complex_material_type_spec.rb new file mode 100644 index 00000000..73473af6 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_material_type_spec.rb @@ -0,0 +1,148 @@ +require 'rails_helper' + +RSpec.describe ComplexMaterialType do + before do + class ExampleWork < ActiveFedora::Base + property :complex_material_type, predicate: ::RDF::Vocab::NimsRdp['material-type'], + class_name:"ComplexMaterialType" + accepts_nested_attributes_for :complex_material_type + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_material_type_attributes: [{ description: 'Foo' }]}) + .complex_material_type + .first + .description + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_material_type_attributes: [{ + description: 'material description', + material_type: 'some value', + material_sub_type: 'some other value' + }] + } + expect(@obj.complex_material_type.first.id).to include('#material_type') + end + + it 'creates a complex material type active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_material_type_attributes: [{ + description: 'material description', + material_type: 'some value', + material_sub_type: 'some other value', + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + label: ['Local'] + }], + }] + } + expect(@obj.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_material_type.first.description).to eq ['material description'] + expect(@obj.complex_material_type.first.material_type).to eq ['some value'] + expect(@obj.complex_material_type.first.material_sub_type).to eq ['some other value'] + expect(@obj.complex_material_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_material_type.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_material_type.first.complex_identifier.first.label).to eq ['Local'] + + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_material_type, reject_if: :all_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a material type active triple resource with just the description' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_material_type_attributes: [{ + description: 'Material description 55' + }] + } + expect(@obj.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_material_type.first.description).to eq ['Material description 55'] + expect(@obj.complex_material_type.first.material_type).to be_empty + expect(@obj.complex_material_type.first.material_sub_type).to be_empty + expect(@obj.complex_material_type.first.complex_identifier).to be_empty + end + + it 'creates a material type active triple resource with just the material_type' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_material_type_attributes: [{ + material_type: 'asdfg' + }] + } + expect(@obj.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_material_type.first.description).to be_empty + expect(@obj.complex_material_type.first.material_type).to eq ['asdfg'] + expect(@obj.complex_material_type.first.material_sub_type).to be_empty + expect(@obj.complex_material_type.first.complex_identifier).to be_empty + end + + it 'creates a material type type active triple resource with just the material_sub_type' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_material_type_attributes: [{ + material_sub_type: 'asdfg' + }] + } + expect(@obj.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_material_type.first.description).to be_empty + expect(@obj.complex_material_type.first.material_type).to be_empty + expect(@obj.complex_material_type.first.material_sub_type).to eq ['asdfg'] + expect(@obj.complex_material_type.first.complex_identifier).to be_empty + end + + it 'creates a material type type active triple resource with just the material_sub_type' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_material_type_attributes: [{ + complex_identifier_attributes: [{ + identifier: 'ewfqwefqwef' + }], + }] + } + expect(@obj.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_material_type.first.description).to be_empty + expect(@obj.complex_material_type.first.material_type).to be_empty + expect(@obj.complex_material_type.first.material_sub_type).to be_empty + expect(@obj.complex_material_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_material_type.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_material_type.first.complex_identifier.first.label).to be_empty + end + + it 'rejects a material type type active triple with no values' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_material_type_attributes: [{ + description: nil, + material_type: '' + }] + } + expect(@obj.complex_material_type).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_organization_spec.rb b/hyrax/spec/models/concerns/complex_organization_spec.rb new file mode 100644 index 00000000..063bda42 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_organization_spec.rb @@ -0,0 +1,134 @@ +require 'rails_helper' + +RSpec.describe ComplexOrganization do + before do + class ExampleWork < ActiveFedora::Base + property :complex_organization, predicate: ::RDF::Vocab::ORG.organization, class_name:"ComplexOrganization" + accepts_nested_attributes_for :complex_organization + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_organization_attributes: [{ organization: 'Foo' }]}) + .complex_organization + .first + .organization + end + it { is_expected.to eq ['Foo'] } + end + + it 'creates an organization active triple resource with an id and all properties' do + @obj = ExampleWork.new + @obj.attributes = { + complex_organization_attributes: [ + { + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'org purpose', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }] + } + ] + } + expect(@obj.complex_organization.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_organization.first.organization).to eq ['Foo'] + expect(@obj.complex_organization.first.sub_organization).to eq ['Bar'] + expect(@obj.complex_organization.first.purpose).to eq ['org purpose'] + expect(@obj.complex_organization.first.complex_identifier.first.identifier).to eq ['1234567'] + expect(@obj.complex_organization.first.complex_identifier.first.scheme).to eq ['Local'] + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_organization_attributes: [ + { + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'org purpose', + } + ] + } + expect(@obj.complex_organization.first.id).to include('#organization') + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_organization, reject_if: :organization_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates an organization active triple resource with organization' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_organization_attributes: [ + { + organization: 'Anamika' + } + ] + } + expect(@obj.complex_organization.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_organization.first.organization).to eq ['Anamika'] + expect(@obj.complex_organization.first.sub_organization).to be_empty + expect(@obj.complex_organization.first.purpose).to be_empty + expect(@obj.complex_organization.first.complex_identifier).to be_empty + end + + + it 'rejects an organization active triple with no organization and only sub_organization' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_organization_attributes: [ + { + sub_organization: 'sub org' + } + ] + } + expect(@obj.complex_organization).to be_empty + end + + it 'rejects an organization active triple with no organization and only purpose' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_organization_attributes: [ + { + purpose: 'Org purpose' + } + ] + } + expect(@obj.complex_organization).to be_empty + end + + it 'rejects an organization active triple with no organization and only identifiers' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_organization_attributes: [ + { + complex_identifier_attributes: [{ + identifier: '123456' + }] + } + ] + } + expect(@obj.complex_organization).to be_empty + end + + end +end diff --git a/hyrax/spec/models/concerns/complex_person_spec.rb b/hyrax/spec/models/concerns/complex_person_spec.rb new file mode 100644 index 00000000..6d969da3 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_person_spec.rb @@ -0,0 +1,250 @@ +require 'rails_helper' + +RSpec.describe ComplexPerson do + before do + class ExampleWork < ActiveFedora::Base + property :complex_person, predicate: ::RDF::Vocab::SIOC.has_creator, class_name:"ComplexPerson" + accepts_nested_attributes_for :complex_person + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + describe 'complex_person_attributes' do + subject do + ExampleWork.new({ + complex_person_attributes: [{ + first_name: 'Foo', + last_name: 'Bar', + name: 'Foo Bar', + email: 'foo.bar@example.com', + role: 'Author', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }], + complex_affiliation_attributes: [{ + job_title: 'Tester', + complex_organization_attributes: [{ + organization: 'Org', + sub_organization: 'Sub org', + purpose: 'org purpose', + complex_identifier_attributes: [{ + identifier: 'werqwerqwer', + scheme: 'Local' + }] + }] + }], + uri: 'http://localhost/person/1234567' + }] + }).complex_person.first + end + + it 'creates a person active triple resource with an id and all properties' do + expect(subject).to be_kind_of ActiveTriples::Resource + expect(subject.id).to include('#person') + expect(subject.first_name).to eq ['Foo'] + expect(subject.last_name).to eq ['Bar'] + expect(subject.name).to eq ['Foo Bar'] + expect(subject.email).to eq ['foo.bar@example.com'] + expect(subject.role).to eq ['Author'] + expect(subject.complex_identifier.first.identifier).to eq ['1234567'] + expect(subject.complex_identifier.first.scheme).to eq ['Local'] + expect(subject.complex_affiliation.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_affiliation.first.job_title).to eq ['Tester'] + expect(subject.complex_affiliation.first.complex_organization.first.organization).to eq ['Org'] + expect(subject.complex_affiliation.first.complex_organization.first.sub_organization).to eq ['Sub org'] + expect(subject.complex_affiliation.first.complex_organization.first.purpose).to eq ['org purpose'] + expect(subject.complex_affiliation.first.complex_organization.first.complex_identifier.first.identifier).to eq ['werqwerqwer'] + expect(subject.complex_affiliation.first.complex_organization.first.complex_identifier.first.scheme).to eq ['Local'] + expect(subject.uri).to eq ['http://localhost/person/1234567'] + end + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_person_attributes: [{uri: '#something'}]}) + .complex_person + .first + .uri + end + it { is_expected.to eq ['#something'] } + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_person, reject_if: :person_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + context 'accepts valid complex_person_attributes' do + subject do + ExampleWork2 + .new({ complex_person_attributes: complex_person_attributes }) + .complex_person + .first + end + + context 'name' do + let(:complex_person_attributes) { [{name: 'Anamika'}] } + + it 'creates a person active triple resource with name' do + expect(subject).to be_kind_of ActiveTriples::Resource + expect(subject.name).to eq ['Anamika'] + expect(subject.first_name).to be_empty + expect(subject.last_name).to be_empty + expect(subject.email).to be_empty + expect(subject.role).to be_empty + expect(subject.complex_identifier).to be_empty + expect(subject.complex_affiliation).to be_empty + expect(subject.uri).to be_empty + end + end + + context 'first_name' do + let(:complex_person_attributes) { [{first_name: 'Anamika'}] } + + it 'creates a person active triple resource with first name' do + expect(subject).to be_kind_of ActiveTriples::Resource + expect(subject.name).to be_empty + expect(subject.first_name).to eq ['Anamika'] + expect(subject.last_name).to be_empty + expect(subject.email).to be_empty + expect(subject.role).to be_empty + expect(subject.complex_identifier).to be_empty + expect(subject.complex_affiliation).to be_empty + expect(subject.uri).to be_empty + end + end + + context 'last_name' do + let(:complex_person_attributes) { [{last_name: 'Anamika'}] } + + it 'creates a person active triple resource with last name' do + expect(subject).to be_kind_of ActiveTriples::Resource + expect(subject.name).to be_empty + expect(subject.first_name).to be_empty + expect(subject.last_name).to eq ['Anamika'] + expect(subject.email).to be_empty + expect(subject.role).to be_empty + expect(subject.complex_identifier).to be_empty + expect(subject.complex_affiliation).to be_empty + expect(subject.uri).to be_empty + end + end + + context 'name, affiliation and role' do + let(:complex_person_attributes) do + [{ + name: 'Anamika', + complex_affiliation_attributes: [{ + job_title: 'Paradise', + }], + role: 'Creator' + }] + end + + it 'creates a person active triple resource with name, affiliation and role' do + expect(subject).to be_kind_of ActiveTriples::Resource + expect(subject.name).to eq ['Anamika'] + expect(subject.first_name).to be_empty + expect(subject.last_name).to be_empty + expect(subject.email).to be_empty + expect(subject.role).to eq ['Creator'] + expect(subject.complex_identifier).to be_empty + expect(subject.uri).to be_empty + expect(subject.complex_affiliation.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_affiliation.first.job_title).to eq ['Paradise'] + expect(subject.complex_affiliation.first.complex_organization).to be_empty + end + end + + context 'name, affiliation org and role' do + let(:complex_person_attributes) do + [{ + name: 'Anamika', + complex_affiliation_attributes: [{ + complex_organization_attributes: [{ organization: 'My department' }] + }], + role: 'Creator' + }] + end + + it 'creates a person active triple resource with name, affiliation org and role' do + expect(subject).to be_kind_of ActiveTriples::Resource + expect(subject.name).to eq ['Anamika'] + expect(subject.first_name).to be_empty + expect(subject.last_name).to be_empty + expect(subject.email).to be_empty + expect(subject.role).to eq ['Creator'] + expect(subject.complex_identifier).to be_empty + expect(subject.uri).to be_empty + expect(subject.complex_affiliation.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_affiliation.first.job_title).to be_empty + expect(subject.complex_affiliation.first.complex_organization.first).to be_kind_of ActiveTriples::Resource + expect(subject.complex_affiliation.first.complex_organization.first.organization).to eq ['My department'] + end + end + end + + context 'rejects person active triple with invalid complex_person_attributes' do + subject do + ExampleWork2 + .new({ complex_person_attributes: complex_person_attributes }) + .complex_person + end + + context 'no name and only uri' do + let(:complex_person_attributes) { [{ uri: 'http://example.com/person/123456' }] } + it { is_expected.to be_empty } + end + + context 'no name and only role' do + let(:complex_person_attributes) { [{ role: 'Creator' }] } + it { is_expected.to be_empty } + end + + context 'no name and only affiliation' do + let(:complex_person_attributes) do + [{ + complex_affiliation_attributes: [{ + job_title: 'Paradise', + complex_organization_attributes: [{ + organization: 'My department' + }] + }] + }] + end + it { is_expected.to be_empty } + end + + context 'no name and only identifiers' do + let(:complex_person_attributes) do + [{ + complex_identifier_attributes: [{ + identifier: '123456' + }] + }] + end + it { is_expected.to be_empty } + end + + context 'no name and only email' do + let(:complex_person_attributes) { [{ email: 'me@me.org' }] } + it { is_expected.to be_empty } + end + end + end +end diff --git a/hyrax/spec/models/concerns/complex_purchase_record_spec.rb b/hyrax/spec/models/concerns/complex_purchase_record_spec.rb new file mode 100644 index 00000000..8cc791a5 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_purchase_record_spec.rb @@ -0,0 +1,153 @@ +require 'rails_helper' + +RSpec.describe ComplexPurchaseRecord do + before do + class ExampleWork < ActiveFedora::Base + property :complex_purchase_record, predicate: ::RDF::Vocab::NimsRdp['purchase-record'], + class_name:"ComplexPurchaseRecord" + accepts_nested_attributes_for :complex_purchase_record + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_purchase_record_attributes: [{ title: 'Foo' }]}) + .complex_purchase_record + .first + .title + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_purchase_record_attributes: [{ + date: ['2018-01-28'], + title: 'Instrument 1' + }] + } + expect(@obj.complex_purchase_record.first.id).to include('#purchase_record') + end + + it 'creates a purchase record active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_purchase_record_attributes: [{ + date: ['2018-02-14'], + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['Local'] + }], + supplier_attributes: [{ + organization: 'Fooss', + sub_organization: 'Barss', + purpose: 'Supplier', + complex_identifier_attributes: [{ + identifier: '123456789ss', + scheme: 'Local' + }] + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: '123456789m', + scheme: 'Local' + }] + }], + purchase_record_item: ['Has a purchase record item'], + title: 'Purchase record title' + }] + } + expect(@obj.complex_purchase_record.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_purchase_record.first.id).to include('#purchase_record') + expect(@obj.complex_purchase_record.first.date).to eq ['2018-02-14'] + expect(@obj.complex_purchase_record.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_purchase_record.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_purchase_record.first.complex_identifier.first.label).to eq ['Local'] + expect(@obj.complex_purchase_record.first.supplier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_purchase_record.first.supplier.first.organization).to eq ['Fooss'] + expect(@obj.complex_purchase_record.first.supplier.first.sub_organization).to eq ['Barss'] + expect(@obj.complex_purchase_record.first.supplier.first.purpose).to eq ['Supplier'] + expect(@obj.complex_purchase_record.first.supplier.first.complex_identifier.first.identifier).to eq ['123456789ss'] + expect(@obj.complex_purchase_record.first.supplier.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_purchase_record.first.manufacturer.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_purchase_record.first.manufacturer.first.organization).to eq ['Foo'] + expect(@obj.complex_purchase_record.first.manufacturer.first.sub_organization).to eq ['Bar'] + expect(@obj.complex_purchase_record.first.manufacturer.first.purpose).to eq ['Manufacturer'] + expect(@obj.complex_purchase_record.first.manufacturer.first.complex_identifier.first.identifier).to eq ['123456789m'] + expect(@obj.complex_purchase_record.first.manufacturer.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_purchase_record.first.purchase_record_item).to eq ['Has a purchase record item'] + expect(@obj.complex_purchase_record.first.title).to eq ['Purchase record title'] + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_purchase_record, reject_if: :purchase_record_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a purchase record active triple resource with date and title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_purchase_record_attributes: [{ + date: ['2018-01-28'], + title: 'Purchase record title' + }] + } + expect(@obj.complex_purchase_record.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_purchase_record.first.id).to include('#purchase_record') + expect(@obj.complex_purchase_record.first.date).to eq ['2018-01-28'] + expect(@obj.complex_purchase_record.first.title).to eq ['Purchase record title'] + end + + it 'rejects a purchase record active triple with no date' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_purchase_record_attributes: [{ + title: 'Purchase record title' + }] + } + expect(@obj.complex_purchase_record).to be_empty + end + + it 'rejects a purchase record active triple with no title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_purchase_record_attributes: [{ + date: ['2018-01-28'], + }] + } + expect(@obj.complex_purchase_record).to be_empty + end + + it 'rejects an instrument active triple with no date and title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_purchase_record_attributes: [{ + complex_identifier: [{ + identifier: 'ewfqwefqwef' + }], + }] + } + expect(@obj.complex_purchase_record).to be_empty + end + + end +end diff --git a/hyrax/spec/models/concerns/complex_relation_spec.rb b/hyrax/spec/models/concerns/complex_relation_spec.rb new file mode 100644 index 00000000..3144fd6d --- /dev/null +++ b/hyrax/spec/models/concerns/complex_relation_spec.rb @@ -0,0 +1,290 @@ +require 'rails_helper' + +RSpec.describe ComplexRelation do + before do + class ExampleWork < ActiveFedora::Base + property :complex_relation, predicate: ::RDF::Vocab::DC.relation, + class_name:"ComplexRelation" + accepts_nested_attributes_for :complex_relation + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_relation_attributes: [{ title: 'Foo' }]}) + .complex_relation + .first + .title + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_relation_attributes: [ + { + title: 'A relation title', + url: 'http://example.com/relation', + relationship: 'IsPartOf' + } + ] + } + expect(@obj.complex_relation.first.id).to include('#relation') + end + + it 'creates a relation active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_relation_attributes: [ + { + title: 'My first publication', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['local'] + }], + relationship: 'IsPartOf' + } + ] + } + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to eq ['My first publication'] + expect(@obj.complex_relation.first.url).to eq ['http://example.com/relation'] + expect(@obj.complex_relation.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_relation.first.complex_identifier.first.label).to eq ['local'] + expect(@obj.complex_relation.first.relationship).to eq ['IsPartOf'] + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_relation, reject_if: :relation_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a relation active triple resource with title and relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + title: 'A relation title', + relationship: 'IsPartOf' + } + ] + } + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to eq ['A relation title'] + expect(@obj.complex_relation.first.url).to be_empty + expect(@obj.complex_relation.first.complex_identifier).to be_empty + expect(@obj.complex_relation.first.relationship).to eq ['IsPartOf'] + end + + it 'creates a relation active triple resource with url and relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + url: 'http://example.com/relation', + relationship: 'isPreviousVersionOf' + } + ] + } + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to be_empty + expect(@obj.complex_relation.first.url).to eq ['http://example.com/relation'] + expect(@obj.complex_relation.first.complex_identifier).to be_empty + expect(@obj.complex_relation.first.relationship).to eq ['isPreviousVersionOf'] + end + + it 'creates a relation active triple resource with identifier and relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + complex_identifier_attributes: [{ + identifier: ['123456'] + }], + relationship: 'isSupplementTo' + } + ] + } + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to be_empty + expect(@obj.complex_relation.first.url).to be_empty + expect(@obj.complex_relation.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_relation.first.complex_identifier.first.label).to be_empty + expect(@obj.complex_relation.first.relationship).to eq ['isSupplementTo'] + end + + it 'creates a relation active triple resource with title, url and relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + title: 'A relation title', + url: 'http://example.com/relation', + relationship: 'isContinuedBy' + } + ] + } + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to eq ['A relation title'] + expect(@obj.complex_relation.first.url).to eq ['http://example.com/relation'] + expect(@obj.complex_relation.first.complex_identifier).to be_empty + expect(@obj.complex_relation.first.relationship).to eq ['isContinuedBy'] + end + + it 'creates a relation active triple resource with title, identifier and relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + title: 'A relation title', + complex_identifier_attributes: [{ + identifier: ['123456'] + }], + relationship: 'isContinuedBy' + } + ] + } + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to eq ['A relation title'] + expect(@obj.complex_relation.first.url).to be_empty + expect(@obj.complex_relation.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_relation.first.complex_identifier.first.label).to be_empty + expect(@obj.complex_relation.first.relationship).to eq ['isContinuedBy'] + end + + it 'creates a relation active triple resource with title, url, identifier and relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + title: 'A relation title', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: 'Local' + }], + relationship: 'isDocumentedBy' + } + ] + } + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to eq ['A relation title'] + expect(@obj.complex_relation.first.url).to eq ['http://example.com/relation'] + expect(@obj.complex_relation.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_relation.first.complex_identifier.first.label).to eq ['Local'] + expect(@obj.complex_relation.first.relationship).to eq ['isDocumentedBy'] + end + + it 'creates a relation active triple resource with url, identifier and relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: 'Local' + }], + relationship: 'isDerivedFrom' + } + ] + } + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.url).to eq ['http://example.com/relation'] + expect(@obj.complex_relation.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_relation.first.complex_identifier.first.label).to eq ['Local'] + expect(@obj.complex_relation.first.relationship).to eq ['isDerivedFrom'] + end + + it 'rejects relation active triple with just title and no relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + title: 'Local' + } + ] + } + expect(@obj.complex_relation).to be_empty + end + + it 'rejects relation active triple with just url and no relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + url: 'http://example.com/relation' + } + ] + } + expect(@obj.complex_relation).to be_empty + end + + it 'rejects relation active triple with just identifier and no relationship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + complex_identifier_attributes: [{ + identifier: ['123456'], + label: 'Local' + }], + } + ] + } + expect(@obj.complex_relation).to be_empty + end + + it 'rejects relation active triple with just reltionship and no identifying information' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + relationship: 'isPartOf' + } + ] + } + expect(@obj.complex_relation).to be_empty + end + + it 'rejects relation active triple with no reltionship' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_relation_attributes: [ + { + title: 'test relation', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: 'Local' + }] + } + ] + } + expect(@obj.complex_relation).to be_empty + end + + end +end diff --git a/hyrax/spec/models/concerns/complex_rights_spec.rb b/hyrax/spec/models/concerns/complex_rights_spec.rb new file mode 100644 index 00000000..8cca8c93 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_rights_spec.rb @@ -0,0 +1,90 @@ +require 'rails_helper' + +RSpec.describe ComplexRights do + before do + class ExampleWork < ActiveFedora::Base + property :complex_rights, predicate: ::RDF::Vocab::DC11.rights, + class_name:"ComplexRights" + accepts_nested_attributes_for :complex_rights + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_rights_attributes: [{ rights: 'Foo' }]}) + .complex_rights + .first + .rights + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_rights_attributes: [{ + rights: 'https://creativecommons.org/publicdomain/zero/1.0/' + }] + } + expect(@obj.complex_rights.first.id).to include('#rights') + end + + it 'creates a rights active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_rights_attributes: [{ + date: '1978-10-28', + rights: 'https://creativecommons.org/publicdomain/zero/1.0/', + label: 'CC-0' + }] + } + expect(@obj.complex_rights.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_rights.first.date).to eq ['1978-10-28'] + expect(@obj.complex_rights.first.rights).to eq ['https://creativecommons.org/publicdomain/zero/1.0/'] + expect(@obj.complex_rights.first.label).to eq ['CC-0'] + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_rights, reject_if: :rights_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a rights active triple resource with just the rights' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_rights_attributes: [{ + rights: 'https://creativecommons.org/publicdomain/zero/1.0/' + }] + } + expect(@obj.complex_rights.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_rights.first.rights).to eq ['https://creativecommons.org/publicdomain/zero/1.0/'] + expect(@obj.complex_rights.first.date).to be_empty + end + + it 'rejects a rights active triple with no rights' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_rights_attributes: [{ + date: '2018-01-01', + label: 'cc0' + }] + } + expect(@obj.complex_rights).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_shape_spec.rb b/hyrax/spec/models/concerns/complex_shape_spec.rb new file mode 100644 index 00000000..593ad79d --- /dev/null +++ b/hyrax/spec/models/concerns/complex_shape_spec.rb @@ -0,0 +1,122 @@ +require 'rails_helper' + +RSpec.describe ComplexShape do + before do + class ExampleWork < ActiveFedora::Base + property :complex_shape, predicate: ::RDF::Vocab::NimsRdp.shape, + class_name:"ComplexShape" + accepts_nested_attributes_for :complex_shape + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_shape_attributes: [{ description: 'Foo' }]}) + .complex_shape + .first + .description + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_shape_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }], + description: 'shape 1' + }] + } + expect(@obj.complex_shape.first.id).to include('#shape') + end + + it 'creates a shape active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_shape_attributes: [{ + description: 'shape description', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['Local'] + }] + }] + } + expect(@obj.complex_shape.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_shape.first.id).to include('#shape') + expect(@obj.complex_shape.first.description).to eq ['shape description'] + expect(@obj.complex_shape.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_shape.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_shape.first.complex_identifier.first.label).to eq ['Local'] + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_shape, reject_if: :identifier_description_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a shape active triple resource with description and identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_shape_attributes: [{ + description: 'chemical composition 12', + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + } + expect(@obj.complex_shape.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_shape.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_shape.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_shape.first.description).to eq ['chemical composition 12'] + end + + it 'rejects a shape active triple with no description' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_shape_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + } + expect(@obj.complex_shape).to be_empty + end + + it 'rejects a shape active triple with no identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_shape_attributes: [{ + description: 'composition 1' + }] + } + expect(@obj.complex_shape).to be_empty + @obj2 = ExampleWork2.new + @obj2.attributes = { + complex_shape_attributes: [{ + description: 'shape description', + complex_identifier_attributes: [{ + label: ['Local'] + }] + }] + } + expect(@obj2.complex_shape).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_source_spec.rb b/hyrax/spec/models/concerns/complex_source_spec.rb new file mode 100644 index 00000000..ff53e775 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_source_spec.rb @@ -0,0 +1,244 @@ +require 'rails_helper' + +RSpec.describe ComplexSource do + before do + class ExampleWork < ActiveFedora::Base + property :complex_source, predicate: ::RDF::Vocab::ESciDocPublication.source, class_name:"ComplexSource" + accepts_nested_attributes_for :complex_source + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_source_attributes: [{ title: 'Foo' }]}) + .complex_source + .first + .title + end + it { is_expected.to eq ['Foo'] } + end + + it 'creates a complex source active triple resource with an id and all properties' do + @obj = ExampleWork.new + @obj.attributes = { + complex_source_attributes: [ + { + alternative_title: 'Sub title for journal', + complex_person_attributes: [{ + name: 'AR', + role: 'Editor' + }], + end_page: '12', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }], + issue: '34', + sequence_number: '1.2.2', + start_page: '4', + title: 'Test journal', + total_number_of_pages: '8', + volume: '3' + } + ] + } + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.alternative_title).to eq ['Sub title for journal'] + expect(@obj.complex_source.first.complex_person.first.name).to eq ['AR'] + expect(@obj.complex_source.first.complex_person.first.role).to eq ['Editor'] + expect(@obj.complex_source.first.end_page).to eq ['12'] + expect(@obj.complex_source.first.complex_identifier.first.identifier).to eq ['1234567'] + expect(@obj.complex_source.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_source.first.issue).to eq ['34'] + expect(@obj.complex_source.first.sequence_number).to eq ['1.2.2'] + expect(@obj.complex_source.first.start_page).to eq ['4'] + expect(@obj.complex_source.first.title).to eq ['Test journal'] + expect(@obj.complex_source.first.total_number_of_pages).to eq ['8'] + expect(@obj.complex_source.first.volume).to eq ['3'] + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_source_attributes: [ + { + title: 'Test journal' + } + ] + } + expect(@obj.complex_source.first.id).to include('#source') + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + accepts_nested_attributes_for :complex_source, reject_if: :all_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a source active triple resource with title' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_source_attributes: [ + { + title: 'Anamika' + } + ] + } + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.alternative_title).to be_empty + expect(@obj.complex_source.first.title).to eq ['Anamika'] + expect(@obj.complex_source.first.complex_person).to be_empty + expect(@obj.complex_source.first.end_page).to be_empty + expect(@obj.complex_source.first.complex_identifier).to be_empty + expect(@obj.complex_source.first.issue).to be_empty + expect(@obj.complex_source.first.sequence_number).to be_empty + expect(@obj.complex_source.first.start_page).to be_empty + expect(@obj.complex_source.first.total_number_of_pages).to be_empty + expect(@obj.complex_source.first.volume).to be_empty + end + + it 'creates a source active triple resource with complex_person' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_source_attributes: [ + { + complex_person_attributes: [{name: 'Anamika'}] + } + ] + } + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.alternative_title).to be_empty + expect(@obj.complex_source.first.title).to be_empty + expect(@obj.complex_source.first.complex_person.first.name).to eq ['Anamika'] + expect(@obj.complex_source.first.end_page).to be_empty + expect(@obj.complex_source.first.complex_identifier).to be_empty + expect(@obj.complex_source.first.issue).to be_empty + expect(@obj.complex_source.first.sequence_number).to be_empty + expect(@obj.complex_source.first.start_page).to be_empty + expect(@obj.complex_source.first.total_number_of_pages).to be_empty + expect(@obj.complex_source.first.volume).to be_empty + end + + it 'creates a source active triple resource with complex_identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_source_attributes: [ + { + complex_identifier_attributes: [{identifier: '1234567'}] + } + ] + } + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.alternative_title).to be_empty + expect(@obj.complex_source.first.title).to be_empty + expect(@obj.complex_source.first.complex_person).to be_empty + expect(@obj.complex_source.first.end_page).to be_empty + expect(@obj.complex_source.first.complex_identifier.first.identifier).to eq ['1234567'] + expect(@obj.complex_source.first.issue).to be_empty + expect(@obj.complex_source.first.sequence_number).to be_empty + expect(@obj.complex_source.first.start_page).to be_empty + expect(@obj.complex_source.first.total_number_of_pages).to be_empty + expect(@obj.complex_source.first.volume).to be_empty + end + + it 'creates a source active triple resource with issue' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_source_attributes: [ + { + issue: '12' + } + ] + } + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.alternative_title).to be_empty + expect(@obj.complex_source.first.title).to be_empty + expect(@obj.complex_source.first.complex_person).to be_empty + expect(@obj.complex_source.first.end_page).to be_empty + expect(@obj.complex_source.first.complex_identifier).to be_empty + expect(@obj.complex_source.first.issue).to eq ['12'] + expect(@obj.complex_source.first.sequence_number).to be_empty + expect(@obj.complex_source.first.start_page).to be_empty + expect(@obj.complex_source.first.total_number_of_pages).to be_empty + expect(@obj.complex_source.first.volume).to be_empty + end + + it 'creates a source active triple resource with sequence_number' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_source_attributes: [ + { + sequence_number: '1.45' + } + ] + } + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.alternative_title).to be_empty + expect(@obj.complex_source.first.title).to be_empty + expect(@obj.complex_source.first.complex_person).to be_empty + expect(@obj.complex_source.first.end_page).to be_empty + expect(@obj.complex_source.first.complex_identifier).to be_empty + expect(@obj.complex_source.first.issue).to be_empty + expect(@obj.complex_source.first.sequence_number).to eq ['1.45'] + expect(@obj.complex_source.first.start_page).to be_empty + expect(@obj.complex_source.first.total_number_of_pages).to be_empty + expect(@obj.complex_source.first.volume).to be_empty + end + + it 'creates a source active triple resource with volume' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_source_attributes: [ + { + volume: '145' + } + ] + } + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.alternative_title).to be_empty + expect(@obj.complex_source.first.title).to be_empty + expect(@obj.complex_source.first.complex_person).to be_empty + expect(@obj.complex_source.first.end_page).to be_empty + expect(@obj.complex_source.first.complex_identifier).to be_empty + expect(@obj.complex_source.first.issue).to be_empty + expect(@obj.complex_source.first.sequence_number).to be_empty + expect(@obj.complex_source.first.start_page).to be_empty + expect(@obj.complex_source.first.total_number_of_pages).to be_empty + expect(@obj.complex_source.first.volume).to eq ['145'] + end + + it 'rejects source active triple with no values' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_source_attributes: [ + { + title: '' + } + ] + } + @obj2 = ExampleWork2.new + @obj2.attributes = { + complex_source_attributes: [ + { + sequence_number: nil + } + ] + } + expect(@obj.complex_source).to be_empty + expect(@obj2.complex_source).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_specimen_type_spec.rb b/hyrax/spec/models/concerns/complex_specimen_type_spec.rb new file mode 100644 index 00000000..22c1cae5 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_specimen_type_spec.rb @@ -0,0 +1,659 @@ +require 'rails_helper' + +RSpec.describe ComplexSpecimenType do + before do + class ExampleWork < ActiveFedora::Base + property :complex_specimen_type, predicate: ::RDF::Vocab::NimsRdp['specimen-type'], + class_name:"ComplexSpecimenType" + accepts_nested_attributes_for :complex_specimen_type + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_specimen_type_attributes: [{ title: 'Foo' }]}) + .complex_specimen_type + .first + .title + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1' + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1' + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: '1234567' + }], + complex_material_type_attributes: [{ + description: 'material description', + material_type: 'some material type', + material_sub_type: 'some other material sub type' + }], + complex_structural_feature_attributes: [{ + description: 'structural feature description', + category: 'structural feature category', + sub_category: 'structural feature sub category' + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type.first.id).to include('#specimen_type') + end + + it 'creates a specimen type active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + complex_identifier_attributes: [{ + identifier: 'chemical_composition/1234567' + }], + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + complex_identifier_attributes: [{ + identifier: ['crystallographic_structure/123456'], + label: ['Local'] + }], + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + description: 'material description', + material_type: 'some material type', + material_sub_type: 'some other material sub type', + complex_identifier_attributes: [{ + identifier: ['material/ewfqwefqwef'], + label: ['Local'] + }], + }], + complex_purchase_record_attributes: [{ + date: ['2018-02-14'], + complex_identifier_attributes: [{ + identifier: ['purchase_record/123456'], + label: ['Local'] + }], + supplier_attributes: [{ + organization: 'Fooss', + sub_organization: 'Barss', + purpose: 'Supplier', + complex_identifier_attributes: [{ + identifier: 'supplier/123456789', + scheme: 'Local' + }] + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + complex_identifier_attributes: [{ + identifier: 'manufacturer/123456789', + scheme: 'Local' + }] + }], + purchase_record_item: ['Has a purchase record item'], + title: 'Purchase record title' + }], + complex_shape_attributes: [{ + description: 'shape description', + complex_identifier_attributes: [{ + identifier: ['shape/123456'], + label: ['Local'] + }] + }], + complex_state_of_matter_attributes: [{ + description: 'state of matter description', + complex_identifier_attributes: [{ + identifier: ['state/123456'], + label: ['Local'] + }] + }], + complex_structural_feature_attributes: [{ + description: 'structural feature description', + category: 'structural feature category', + sub_category: 'structural feature sub category', + complex_identifier_attributes: [{ + identifier: ['structural_feature/123456'], + label: ['Local'] + }] + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type.first).to be_kind_of ActiveTriples::Resource + # chemical composition + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.id).to include('#chemical_composition') + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.description).to eq ['chemical composition 1'] + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier.first.identifier).to eq ['chemical_composition/1234567'] + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier.first.label).to be_empty + # crystallographic structure + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.id).to include('#crystallographic_structure') + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.description).to eq ['crystallographic_structure 1'] + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier.first.identifier).to eq ['crystallographic_structure/123456'] + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier.first.label).to eq ['Local'] + # description + expect(@obj.complex_specimen_type.first.description).to eq ['Specimen description'] + # identifier + expect(@obj.complex_specimen_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_identifier.first.id).to include('#identifier') + expect(@obj.complex_specimen_type.first.complex_identifier.first.identifier).to eq ['specimen/1234567'] + # material type + expect(@obj.complex_specimen_type.first.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_material_type.first.id).to include('#material_type') + expect(@obj.complex_specimen_type.first.complex_material_type.first.description).to eq ['material description'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_type).to eq ['some material type'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_sub_type).to eq ['some other material sub type'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier.first.identifier).to eq ['material/ewfqwefqwef'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier.first.label).to eq ['Local'] + # purchase record + expect(@obj.complex_specimen_type.first.complex_purchase_record.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.id).to include('#purchase_record') + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.date).to eq ['2018-02-14'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.complex_identifier.first.identifier).to eq ['purchase_record/123456'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.complex_identifier.first.label).to eq ['Local'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.organization).to eq ['Fooss'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.sub_organization).to eq ['Barss'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.purpose).to eq ['Supplier'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.complex_identifier.first.identifier).to eq ['supplier/123456789'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.organization).to eq ['Foo'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.sub_organization).to eq ['Bar'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.purpose).to eq ['Manufacturer'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.complex_identifier.first.identifier).to eq ['manufacturer/123456789'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.purchase_record_item).to eq ['Has a purchase record item'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.title).to eq ['Purchase record title'] + # shape + expect(@obj.complex_specimen_type.first.complex_shape.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_shape.first.id).to include('#shape') + expect(@obj.complex_specimen_type.first.complex_shape.first.description).to eq ['shape description'] + expect(@obj.complex_specimen_type.first.complex_shape.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_shape.first.complex_identifier.first.identifier).to eq ['shape/123456'] + expect(@obj.complex_specimen_type.first.complex_shape.first.complex_identifier.first.label).to eq ['Local'] + # state of matter + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.id).to include('#state_of_matter') + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.description).to eq ['state of matter description'] + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.complex_identifier.first.identifier).to eq ['state/123456'] + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.complex_identifier.first.label).to eq ['Local'] + # structural feature + expect(@obj.complex_specimen_type.first.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.id).to include('#structural_feature') + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.description).to eq ['structural feature description'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.category).to eq ['structural feature category'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.sub_category).to eq ['structural feature sub category'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier.first.identifier).to eq ['structural_feature/123456'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier.first.label).to eq ['Local'] + # title + expect(@obj.complex_specimen_type.first.title).to eq ['Specimen 1'] + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_specimen_type, reject_if: :specimen_type_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + describe 'creates a specimen type active triple resource with the 7 required attributes' do + it 'with material description and structural description' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + description: 'material description' + }], + complex_structural_feature_attributes: [{ + description: 'structural feature description' + }], + title: 'Specimen 1' + }] + } + # chemical composition + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.id).to include('#chemical_composition') + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.description).to eq ['chemical composition 1'] + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier).to be_empty + # crystallographic structure + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.id).to include('#crystallographic_structure') + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.description).to eq ['crystallographic_structure 1'] + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier).to be_empty + # description + expect(@obj.complex_specimen_type.first.description).to eq ['Specimen description'] + # identifier + expect(@obj.complex_specimen_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_identifier.first.id).to include('#identifier') + expect(@obj.complex_specimen_type.first.complex_identifier.first.identifier).to eq ['specimen/1234567'] + # material type + expect(@obj.complex_specimen_type.first.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_material_type.first.id).to include('#material_type') + expect(@obj.complex_specimen_type.first.complex_material_type.first.description).to eq ['material description'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_type).to be_empty + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_sub_type).to be_empty + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier).to be_empty + # purchase record + expect(@obj.complex_specimen_type.first.complex_purchase_record).to be_empty + # shape + expect(@obj.complex_specimen_type.first.complex_shape).to be_empty + # state of matter + expect(@obj.complex_specimen_type.first.complex_state_of_matter).to be_empty + # structural feature + expect(@obj.complex_specimen_type.first.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.id).to include('#structural_feature') + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.description).to eq ['structural feature description'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.category).to be_empty + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.sub_category).to be_empty + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier).to be_empty + # title + expect(@obj.complex_specimen_type.first.title).to eq ['Specimen 1'] + end + + it 'with material type and structural category' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + material_type: 'some material type', + }], + complex_structural_feature_attributes: [{ + category: 'structural feature category', + }], + title: 'Specimen 1' + }] + } + # chemical composition + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.id).to include('#chemical_composition') + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.description).to eq ['chemical composition 1'] + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier).to be_empty + # crystallographic structure + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.id).to include('#crystallographic_structure') + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.description).to eq ['crystallographic_structure 1'] + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier).to be_empty + # description + expect(@obj.complex_specimen_type.first.description).to eq ['Specimen description'] + # identifier + expect(@obj.complex_specimen_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_identifier.first.id).to include('#identifier') + expect(@obj.complex_specimen_type.first.complex_identifier.first.identifier).to eq ['specimen/1234567'] + # material type + expect(@obj.complex_specimen_type.first.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_material_type.first.id).to include('#material_type') + expect(@obj.complex_specimen_type.first.complex_material_type.first.description).to be_empty + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_type).to eq ['some material type'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_sub_type).to be_empty + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier).to be_empty + # purchase record + expect(@obj.complex_specimen_type.first.complex_purchase_record).to be_empty + # shape + expect(@obj.complex_specimen_type.first.complex_shape).to be_empty + # state of matter + expect(@obj.complex_specimen_type.first.complex_state_of_matter).to be_empty + # structural feature + expect(@obj.complex_specimen_type.first.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.id).to include('#structural_feature') + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.description).to be_empty + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.category).to eq ['structural feature category'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.sub_category).to be_empty + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier).to be_empty + # title + expect(@obj.complex_specimen_type.first.title).to eq ['Specimen 1'] + end + + it 'with material sub type and structural sub category' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + material_sub_type: 'some sub material type', + }], + complex_structural_feature_attributes: [{ + sub_category: 'structural feature sub category', + }], + title: 'Specimen 1' + }] + } + # chemical composition + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.id).to include('#chemical_composition') + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.description).to eq ['chemical composition 1'] + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier).to be_empty + # crystallographic structure + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.id).to include('#crystallographic_structure') + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.description).to eq ['crystallographic_structure 1'] + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier).to be_empty + # description + expect(@obj.complex_specimen_type.first.description).to eq ['Specimen description'] + # identifier + expect(@obj.complex_specimen_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_identifier.first.id).to include('#identifier') + expect(@obj.complex_specimen_type.first.complex_identifier.first.identifier).to eq ['specimen/1234567'] + # material type + expect(@obj.complex_specimen_type.first.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_material_type.first.id).to include('#material_type') + expect(@obj.complex_specimen_type.first.complex_material_type.first.description).to be_empty + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_type).to be_empty + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_sub_type).to eq ['some sub material type'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier).to be_empty + # purchase record + expect(@obj.complex_specimen_type.first.complex_purchase_record).to be_empty + # shape + expect(@obj.complex_specimen_type.first.complex_shape).to be_empty + # state of matter + expect(@obj.complex_specimen_type.first.complex_state_of_matter).to be_empty + # structural feature + expect(@obj.complex_specimen_type.first.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.id).to include('#structural_feature') + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.description).to be_empty + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.category).to be_empty + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.sub_category).to eq ['structural feature sub category'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier).to be_empty + # title + expect(@obj.complex_specimen_type.first.title).to eq ['Specimen 1'] + end + end + + it 'rejects a specimen type active triple with no chemical composition' do + skip + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + material_sub_type: 'some sub material type', + }], + complex_structural_feature_attributes: [{ + sub_category: 'structural feature sub category', + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type).to be_empty + end + + it 'rejects a specimen type active triple with no crystallographic structure' do + skip + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + material_sub_type: 'some sub material type', + }], + complex_structural_feature_attributes: [{ + sub_category: 'structural feature sub category', + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type).to be_empty + end + + it 'rejects a specimen type active triple with no description' do + skip + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + material_sub_type: 'some sub material type', + }], + complex_structural_feature_attributes: [{ + sub_category: 'structural feature sub category', + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type).to be_empty + end + + it 'rejects a specimen type active triple with no identifier' do + skip + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_material_type_attributes: [{ + material_sub_type: 'some sub material type', + }], + complex_structural_feature_attributes: [{ + sub_category: 'structural feature sub category', + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type).to be_empty + end + + it 'rejects a specimen type active triple with no material types' do + skip + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_structural_feature_attributes: [{ + sub_category: 'structural feature sub category', + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type).to be_empty + end + + it 'rejects a specimen type active triple with no structural features' do + skip + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + material_sub_type: 'some sub material type', + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type).to be_empty + end + + it 'rejects a specimen type active triple with no title' do + skip + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + material_sub_type: 'some sub material type', + }], + complex_structural_feature_attributes: [{ + sub_category: 'structural feature sub category', + }] + }] + } + expect(@obj.complex_specimen_type).to be_empty + end + + it 'rejects a specimen type active triple with some required and some non-required information' do + skip + @obj = ExampleWork2.new + @obj.attributes = { + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + complex_identifier_attributes: [{ + identifier: 'chemical_composition/1234567' + }], + }], + complex_crystallographic_structure_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['crystallographic_structure/123456'], + label: ['Local'] + }], + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['material/ewfqwefqwef'], + label: ['Local'] + }], + }], + complex_purchase_record_attributes: [{ + date: ['2018-02-14'], + complex_identifier_attributes: [{ + identifier: ['purchase_record/123456'], + label: ['Local'] + }], + supplier_attributes: [{ + organization: 'Fooss', + sub_organization: 'Barss', + purpose: 'Supplier', + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + }], + purchase_record_item: ['Has a purchase record item'], + title: 'Purchase record title' + }], + complex_shape_attributes: [{ + description: 'shape description', + }], + complex_state_of_matter_attributes: [{ + description: 'state of matter description', + }], + complex_structural_feature_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['structural_feature/123456'], + label: ['Local'] + }] + }], + title: 'Specimen 1' + }] + } + expect(@obj.complex_specimen_type).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_state_of_matter_spec.rb b/hyrax/spec/models/concerns/complex_state_of_matter_spec.rb new file mode 100644 index 00000000..d4f1ae01 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_state_of_matter_spec.rb @@ -0,0 +1,122 @@ +require 'rails_helper' + +RSpec.describe ComplexStateOfMatter do + before do + class ExampleWork < ActiveFedora::Base + property :complex_state_of_matter, predicate: ::RDF::Vocab::NimsRdp['state-of-matter'], + class_name:"ComplexStateOfMatter" + accepts_nested_attributes_for :complex_state_of_matter + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_state_of_matter_attributes: [{ description: 'Foo' }]}) + .complex_state_of_matter + .first + .description + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_state_of_matter_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }], + description: 'state of matter 1' + }] + } + expect(@obj.complex_state_of_matter.first.id).to include('#state_of_matter') + end + + it 'creates a state of matter active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_state_of_matter_attributes: [{ + description: 'state of matter description', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['Local'] + }] + }] + } + expect(@obj.complex_state_of_matter.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_state_of_matter.first.id).to include('#state_of_matter') + expect(@obj.complex_state_of_matter.first.description).to eq ['state of matter description'] + expect(@obj.complex_state_of_matter.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_state_of_matter.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_state_of_matter.first.complex_identifier.first.label).to eq ['Local'] + end + + describe "when reject_if is a symbol" do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_state_of_matter, reject_if: :identifier_description_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a state of matter active triple resource with description and identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_state_of_matter_attributes: [{ + description: 'chemical composition 12', + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + } + expect(@obj.complex_state_of_matter.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_state_of_matter.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_state_of_matter.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_state_of_matter.first.description).to eq ['chemical composition 12'] + end + + it 'rejects a state of matter active triple with no description' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_state_of_matter_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }] + }] + } + expect(@obj.complex_state_of_matter).to be_empty + end + + it 'rejects a state of matter active triple with no identifier' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_state_of_matter_attributes: [{ + description: 'composition 1' + }] + } + expect(@obj.complex_state_of_matter).to be_empty + @obj2 = ExampleWork2.new + @obj2.attributes = { + complex_state_of_matter_attributes: [{ + description: 'state of matter description', + complex_identifier_attributes: [{ + label: ['Local'] + }] + }] + } + expect(@obj2.complex_state_of_matter).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_structural_feature_spec.rb b/hyrax/spec/models/concerns/complex_structural_feature_spec.rb new file mode 100644 index 00000000..e8fc3a27 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_structural_feature_spec.rb @@ -0,0 +1,149 @@ +require 'rails_helper' + +RSpec.describe ComplexStructuralFeature do + before do + class ExampleWork < ActiveFedora::Base + property :complex_structural_feature, predicate: ::RDF::Vocab::NimsRdp['structural-feature'], + class_name:"ComplexStructuralFeature" + accepts_nested_attributes_for :complex_structural_feature + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_structural_feature_attributes: [{ description: 'Foo' }]}) + .complex_structural_feature + .first + .description + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_structural_feature_attributes: [{ + description: 'structural feature description', + category: 'some value', + sub_category: 'some other value' + }] + } + expect(@obj.complex_structural_feature.first.id).to include('#structural_feature') + end + + it 'creates a complex structural feature type active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_structural_feature_attributes: [{ + description: 'structural feature description', + category: 'some value', + sub_category: 'some other value', + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + label: ['Local'] + }], + }] + } + expect(@obj.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_structural_feature.first.id).to include('#structural_feature') + expect(@obj.complex_structural_feature.first.description).to eq ['structural feature description'] + expect(@obj.complex_structural_feature.first.category).to eq ['some value'] + expect(@obj.complex_structural_feature.first.sub_category).to eq ['some other value'] + expect(@obj.complex_structural_feature.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_structural_feature.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_structural_feature.first.complex_identifier.first.label).to eq ['Local'] + + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_structural_feature, reject_if: :all_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a structural feature type active triple resource with just the description' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_structural_feature_attributes: [{ + description: 'structural feature description 55' + }] + } + expect(@obj.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_structural_feature.first.description).to eq ['structural feature description 55'] + expect(@obj.complex_structural_feature.first.category).to be_empty + expect(@obj.complex_structural_feature.first.sub_category).to be_empty + expect(@obj.complex_structural_feature.first.complex_identifier).to be_empty + end + + it 'creates a structural feature type active triple resource with just the category' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_structural_feature_attributes: [{ + category: 'asdfg' + }] + } + expect(@obj.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_structural_feature.first.description).to be_empty + expect(@obj.complex_structural_feature.first.category).to eq ['asdfg'] + expect(@obj.complex_structural_feature.first.sub_category).to be_empty + expect(@obj.complex_structural_feature.first.complex_identifier).to be_empty + end + + it 'creates a structural feature type type active triple resource with just the sub_category' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_structural_feature_attributes: [{ + sub_category: 'asdfg' + }] + } + expect(@obj.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_structural_feature.first.description).to be_empty + expect(@obj.complex_structural_feature.first.category).to be_empty + expect(@obj.complex_structural_feature.first.sub_category).to eq ['asdfg'] + expect(@obj.complex_structural_feature.first.complex_identifier).to be_empty + end + + it 'creates a structural feature type type active triple resource with just the sub_category' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_structural_feature_attributes: [{ + complex_identifier_attributes: [{ + identifier: 'ewfqwefqwef' + }], + }] + } + expect(@obj.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_structural_feature.first.description).to be_empty + expect(@obj.complex_structural_feature.first.category).to be_empty + expect(@obj.complex_structural_feature.first.sub_category).to be_empty + expect(@obj.complex_structural_feature.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_structural_feature.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_structural_feature.first.complex_identifier.first.label).to be_empty + end + + it 'rejects a structural feature type type active triple with no values' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_structural_feature_attributes: [{ + description: nil, + category: '' + }] + } + expect(@obj.complex_structural_feature).to be_empty + end + end +end diff --git a/hyrax/spec/models/concerns/complex_version_spec.rb b/hyrax/spec/models/concerns/complex_version_spec.rb new file mode 100644 index 00000000..e183dcc6 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_version_spec.rb @@ -0,0 +1,103 @@ +require 'rails_helper' + +RSpec.describe ComplexVersion do + before do + class ExampleWork < ActiveFedora::Base + property :complex_version, predicate: ::RDF::URI.new('http://www.w3.org/2002/07/owl#versionInfo'), + class_name:"ComplexVersion" + accepts_nested_attributes_for :complex_version + end + end + after do + Object.send(:remove_const, :ExampleWork) + end + + context 'uri with a #' do + before do + # special hack to force code path for testing + allow_any_instance_of(RDF::Node).to receive(:node?) { false } + allow_any_instance_of(RDF::Node).to receive(:start_with?) { true } + end + subject do + ExampleWork + .new({ complex_version_attributes: [{ version: 'Foo' }]}) + .complex_version + .first + .version + end + it { is_expected.to eq ['Foo'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_version_attributes: [ + { + version: '1.0' + } + ] + } + expect(@obj.complex_version.first.id).to include('#version') + end + + it 'creates a version active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_version_attributes: [ + { + date: '1978-10-28', + description: 'Creating the first version', + identifier: 'id1', + version: '1.0' + } + ] + } + expect(@obj.complex_version.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_version.first.date).to eq ['1978-10-28'] + expect(@obj.complex_version.first.description).to eq ['Creating the first version'] + expect(@obj.complex_version.first.identifier).to eq ['id1'] + expect(@obj.complex_version.first.version).to eq ['1.0'] + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_version, reject_if: :version_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a version active triple resource with just the version' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_version_attributes: [ + { + version: '1.0' + } + ] + } + expect(@obj.complex_version.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_version.first.version).to eq ['1.0'] + expect(@obj.complex_version.first.date).to be_empty + expect(@obj.complex_version.first.description).to be_empty + expect(@obj.complex_version.first.identifier).to be_empty + end + + it 'rejects a version active triple with no version' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_version_attributes: [ + { + description: 'Local version', + identifier: 'id1', + date: '2018-01-01' + } + ] + } + expect(@obj.complex_version).to be_empty + end + end +end diff --git a/hyrax/spec/models/dataset_spec.rb b/hyrax/spec/models/dataset_spec.rb new file mode 100644 index 00000000..744ac464 --- /dev/null +++ b/hyrax/spec/models/dataset_spec.rb @@ -0,0 +1,928 @@ +# Generated via +# `rails generate hyrax:work Dataset` +require 'rails_helper' + +RSpec.describe Dataset do + it 'has human readable type for the dataset' do + @obj = build(:dataset) + expect(@obj.human_readable_type).to eq('Dataset') + end + + describe 'date_modified' do + it 'has date_modified as singular' do + @obj = build(:dataset, date_modified: '2018/04/23') + expect(@obj.date_modified).to eq '2018/04/23' + end + end + + describe 'date_uploaded' do + it 'has date_uploaded as singular' do + @obj = build(:dataset, date_uploaded: '2018 01 02') + expect(@obj.date_uploaded).to eq '2018 01 02' + end + end + + describe 'depositor' do + it 'has depositor' do + @obj = build(:dataset, depositor: 'Name of depositor') + expect(@obj.depositor).to eq 'Name of depositor' + end + end + + describe 'title' do + it 'requires title' do + @obj = build(:dataset, title: nil) + expect{@obj.save!}.to raise_error(ActiveFedora::RecordInvalid, + 'Validation failed: Title Your dataset must have a title.') + end + + it 'has a multi valued title field' do + @obj = build(:dataset, title: ['test dataset']) + expect(@obj.title).to eq ['test dataset'] + end + end + + describe 'based_near' do + it 'has based_near' do + @obj = build(:dataset, based_near: ['me']) + expect(@obj.based_near).to eq ['me'] + end + end + + describe 'bibliographic_citation' do + it 'has bibliographic_citation' do + @obj = build(:dataset, bibliographic_citation: ['bibliographic_citation 1']) + expect(@obj.bibliographic_citation).to eq ['bibliographic_citation 1'] + end + end + + describe 'contributor' do + it 'has contributor' do + @obj = build(:dataset, contributor: ['contributor 1']) + expect(@obj.contributor).to eq ['contributor 1'] + end + end + + describe 'creator' do + it 'has creator' do + @obj = build(:dataset, creator: ['Creator 1']) + expect(@obj.creator).to eq ['Creator 1'] + end + end + + describe 'date_created' do + it 'has date_created' do + @obj = build(:dataset, date_created: ['date_created 1']) + expect(@obj.date_created).to eq ['date_created 1'] + end + end + + describe 'description' do + it 'has description' do + @obj = build(:dataset, description: ['description 1']) + expect(@obj.description).to eq ['description 1'] + end + end + + describe 'identifier' do + it 'has identifier' do + @obj = build(:dataset, identifier: ['identifier 1']) + expect(@obj.identifier).to eq ['identifier 1'] + end + end + + describe 'import_url' do + it 'has import_url as singular' do + @obj = build(:dataset, import_url: 'http://example.com/import/url') + expect(@obj.import_url).to eq 'http://example.com/import/url' + end + end + + describe 'keyword' do + it 'has keyword' do + @obj = build(:dataset, keyword: ['keyword 1', 'keyword 2']) + expect(@obj.keyword).to eq ['keyword 1', 'keyword 2'] + end + end + + describe 'label' do + it 'has label as singular' do + @obj = build(:dataset, label: 'Label 1') + expect(@obj.label).to eq 'Label 1' + end + end + + describe 'language' do + it 'has language' do + @obj = build(:dataset, language: ['language 1']) + expect(@obj.language).to eq ['language 1'] + end + end + + describe 'part_of' do + it 'has part_of' do + skip 'Not using this field. Raises RSolr::Error::ConnectionRefused when added to index.' + @obj = build(:dataset, part_of: ['Bigger dataset']) + expect(@obj.part_of).to eq ['Bigger dataset'] + end + end + + describe 'publisher' do + it 'has publisher' do + @obj = build(:dataset, publisher: ['publisher 1']) + expect(@obj.publisher).to eq ['publisher 1'] + end + end + + describe 'related_url' do + it 'has related_url' do + @obj = build(:dataset, related_url: ['http://example.com/related/url']) + expect(@obj.related_url).to eq ['http://example.com/related/url'] + end + end + + describe 'relative_path' do + it 'has relative_path as singular' do + @obj = build(:dataset, relative_path: 'relative/path/to/file') + expect(@obj.relative_path).to eq 'relative/path/to/file' + end + end + + describe 'resource_type' do + it 'has resource_type' do + @obj = build(:dataset, resource_type: ['Dataset']) + expect(@obj.resource_type).to eq ['Dataset'] + end + end + + describe 'rights or license' do + it 'has license (saved as dct:rights)' do + @obj = build(:dataset, license: ['CC-0']) + expect(@obj.license).to eq ['CC-0'] + end + end + + describe 'supervisor_approval' do + it 'has supervisor_approval' do + @obj = build(:dataset, supervisor_approval: ['Kosuke Tanabe 2019.08.01']) + expect(@obj.supervisor_approval).to eq ['Kosuke Tanabe 2019.08.01'] + end + end + + describe 'complex_rights' do + it 'creates a complex rights active triple resource with rights' do + @obj = build(:dataset, + complex_rights_attributes: [{ + rights: 'cc0' + }] + ) + expect(@obj.complex_rights.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_rights.first.id).to include('#rights') + expect(@obj.complex_rights.first.rights).to eq ['cc0'] + expect(@obj.complex_rights.first.date).to be_empty + end + + it 'creates a rights active triple resource with all the attributes' do + @obj = build(:dataset, + complex_rights_attributes: [{ + date: '1978-10-28', + rights: 'CC0' + }] + ) + expect(@obj.complex_rights.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_rights.first.date).to eq ['1978-10-28'] + expect(@obj.complex_rights.first.rights).to eq ['CC0'] + end + + it 'rejects a rights active triple with no rights' do + @obj = build(:dataset, + complex_rights_attributes: [{ + date: '2018-01-01' + }] + ) + expect(@obj.complex_rights).to be_empty + end + end + + describe 'rights_statement' do + it 'has rights_statement' do + @obj = build(:dataset, rights_statement: ['rights_statement 1']) + expect(@obj.rights_statement).to eq ['rights_statement 1'] + end + end + + describe 'source' do + it 'has source' do + @obj = build(:dataset, source: ['Source 1']) + expect(@obj.source).to eq ['Source 1'] + end + end + + describe 'subject' do + it 'has subject' do + @obj = build(:dataset, subject: ['subject 1']) + expect(@obj.subject).to eq ['subject 1'] + end + end + + describe 'alternative_title' do + it 'has alternative_title as singular' do + @obj = build(:dataset, alternative_title: 'Alternative Title') + expect(@obj.alternative_title).to eq 'Alternative Title' + end + end + + describe 'complex_date' do + it 'creates a date active triple resource with all the attributes' do + @obj = build(:dataset, + complex_date_attributes: [{ + date: '1978-10-28', + description: 'Some kind of a date', + }] + ) + expect(@obj.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_date.first.date).to eq ['1978-10-28'] + expect(@obj.complex_date.first.description).to eq ['Some kind of a date'] + end + + it 'creates a date active triple resource with just the date' do + @obj = build(:dataset, + complex_date_attributes: [{ + date: '1984-09-01' + }] + ) + expect(@obj.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_date.first.date).to eq ['1984-09-01'] + expect(@obj.complex_date.first.description).to be_empty + end + + it 'rejects a date active triple with no date' do + @obj = build(:dataset, + complex_date_attributes: [{ + description: 'Local date' + }] + ) + expect(@obj.complex_date).to be_empty + end + end + + describe 'complex_identifier' do + it 'creates an identifier active triple resource with all the attributes' do + @obj = build(:dataset, + complex_identifier_attributes: [{ + identifier: '0000-0000-0000-0000', + scheme: 'uri_of_ORCID_scheme', + label: 'ORCID' + }] + ) + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['0000-0000-0000-0000'] + expect(@obj.complex_identifier.first.scheme).to eq ['uri_of_ORCID_scheme'] + expect(@obj.complex_identifier.first.label).to eq ['ORCID'] + end + + it 'creates an identifier active triple resource with just the identifier' do + @obj = build(:dataset, + complex_identifier_attributes: [{ + identifier: '1234' + }] + ) + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['1234'] + expect(@obj.complex_identifier.first.label).to be_empty + expect(@obj.complex_identifier.first.scheme).to be_empty + end + + it 'rejects an identifier active triple with no identifier' do + @obj = build(:dataset, + complex_identifier_attributes: [{ + label: 'Local' + }] + ) + expect(@obj.complex_identifier).to be_empty + end + end + + describe 'complex_person' do + it 'creates a person active triple resource with name' do + @obj = build(:dataset, + complex_person_attributes: [{ + name: 'Anamika' + }] + ) + expect(@obj.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.name).to eq ['Anamika'] + expect(@obj.complex_person.first.first_name).to be_empty + expect(@obj.complex_person.first.last_name).to be_empty + expect(@obj.complex_person.first.email).to be_empty + expect(@obj.complex_person.first.complex_affiliation).to be_empty + expect(@obj.complex_person.first.role).to be_empty + expect(@obj.complex_person.first.complex_identifier).to be_empty + expect(@obj.complex_person.first.uri).to be_empty + end + + it 'creates a person active triple resource with name, affiliation and role' do + @obj = build(:dataset, + complex_person_attributes: [{ + name: 'Anamika', + complex_affiliation_attributes: [{ + job_title: 'Paradise', + }], + role: 'Creator' + }] + ) + expect(@obj.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.name).to eq ['Anamika'] + expect(@obj.complex_person.first.first_name).to be_empty + expect(@obj.complex_person.first.last_name).to be_empty + expect(@obj.complex_person.first.email).to be_empty + expect(@obj.complex_person.first.role).to eq ['Creator'] + expect(@obj.complex_person.first.complex_identifier).to be_empty + expect(@obj.complex_person.first.uri).to be_empty + expect(@obj.complex_person.first.complex_affiliation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.complex_affiliation.first.job_title).to eq ['Paradise'] + end + + it 'rejects person active triple with no name and only uri' do + @obj = build(:dataset, complex_person_attributes: [{ + uri: 'http://example.com/person/123456' + }] + ) + expect(@obj.complex_person).to be_empty + end + end + + describe 'complex_version' do + it 'creates a version active triple resource with all the attributes' do + @obj = build(:dataset, complex_version_attributes: [{ + date: '1978-10-28', + description: 'Creating the first version', + identifier: 'id1', + version: '1.0' + }] + ) + expect(@obj.complex_version.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_version.first.id).to include('#version') + expect(@obj.complex_version.first.date).to eq ['1978-10-28'] + expect(@obj.complex_version.first.description).to eq ['Creating the first version'] + expect(@obj.complex_version.first.identifier).to eq ['id1'] + expect(@obj.complex_version.first.version).to eq ['1.0'] + end + + it 'creates a version active triple resource with just the version' do + @obj = build(:dataset, complex_version_attributes: [{ + version: '1.0' + }] + ) + expect(@obj.complex_version.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_version.first.id).to include('#version') + expect(@obj.complex_version.first.version).to eq ['1.0'] + expect(@obj.complex_version.first.date).to be_empty + expect(@obj.complex_version.first.description).to be_empty + expect(@obj.complex_version.first.identifier).to be_empty + end + + it 'rejects a version active triple with no version' do + @obj = build(:dataset, complex_version_attributes: [{ + description: 'Local version', + identifier: 'id1', + date: '2018-01-01' + }] + ) + expect(@obj.complex_version).to be_empty + end + end + + describe 'complex_organization' do + it 'creates an organization active triple resource with an id and all properties' do + @obj = build(:dataset, complex_organization_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'org purpose', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }] + }] + ) + expect(@obj.complex_organization.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_organization.first.id).to include('#organization') + expect(@obj.complex_organization.first.organization).to eq ['Foo'] + expect(@obj.complex_organization.first.sub_organization).to eq ['Bar'] + expect(@obj.complex_organization.first.purpose).to eq ['org purpose'] + expect(@obj.complex_organization.first.complex_identifier.first.identifier).to eq ['1234567'] + expect(@obj.complex_organization.first.complex_identifier.first.scheme).to eq ['Local'] + end + + it 'creates an organization active triple with organization' do + @obj = build(:dataset, complex_organization_attributes: [{ + organization: 'Foo' + }] + ) + expect(@obj.complex_organization.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_organization.first.organization).to eq ['Foo'] + expect(@obj.complex_organization.first.sub_organization).to be_empty + expect(@obj.complex_organization.first.purpose).to be_empty + expect(@obj.complex_organization.first.complex_identifier).to be_empty + end + + it 'rejects an organization active triple with no organization' do + @obj = build(:dataset, complex_organization_attributes: [{ + sub_organization: 'sub org' + }] + ) + expect(@obj.complex_organization).to be_empty + end + end + + describe 'characterization_methods' do + it 'has characterization_methods' do + @obj = build(:dataset, characterization_methods: ['Characterization methods']) + expect(@obj.characterization_methods).to eq ['Characterization methods'] + end + end + + describe 'computational_methods' do + it 'has computational_methods' do + @obj = build(:dataset, computational_methods: ['computational methods']) + expect(@obj.computational_methods).to eq ['computational methods'] + end + end + + describe 'data_origin' do + it 'has data_origin' do + @obj = build(:dataset, data_origin: ['data origin']) + expect(@obj.data_origin).to eq ['data origin'] + end + end + + describe 'complex_instrument' do + it 'creates an instrument active triple resource with all the attributes' do + @obj = build(:dataset, :with_complex_instrument) + expect(@obj.complex_instrument.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.alternative_title).to eq ['An instrument title'] + expect(@obj.complex_instrument.first.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.complex_date.first.date).to eq ['2018-02-14'] + expect(@obj.complex_instrument.first.description).to eq ['Instrument description'] + expect(@obj.complex_instrument.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.complex_identifier.first.identifier).to eq ['instrument/27213727'] + expect(@obj.complex_instrument.first.complex_identifier.first.label).to eq ['Identifier Persistent'] + expect(@obj.complex_instrument.first.complex_identifier.first.scheme).to eq ['identifier persistent'] + expect(@obj.complex_instrument.first.instrument_function.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.instrument_function.first.column_number).to eq [1] + expect(@obj.complex_instrument.first.instrument_function.first.category).to eq ['some value'] + expect(@obj.complex_instrument.first.instrument_function.first.sub_category).to eq ['some other value'] + expect(@obj.complex_instrument.first.instrument_function.first.description).to eq ['Instrument function description'] + expect(@obj.complex_instrument.first.manufacturer.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.manufacturer.first.organization).to eq ['Foo'] + expect(@obj.complex_instrument.first.manufacturer.first.sub_organization).to eq ['Bar'] + expect(@obj.complex_instrument.first.manufacturer.first.purpose).to eq ['Manufacturer'] + expect(@obj.complex_instrument.first.manufacturer.first.complex_identifier.first.identifier).to eq ['123456789m'] + expect(@obj.complex_instrument.first.manufacturer.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_instrument.first.model_number).to eq ['123xfty'] + expect(@obj.complex_instrument.first.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.complex_person.first.name).to eq ['Name of operator'] + expect(@obj.complex_instrument.first.complex_person.first.role).to eq ['operator'] + expect(@obj.complex_instrument.first.managing_organization.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.managing_organization.first.organization).to eq ['Managing organization name'] + expect(@obj.complex_instrument.first.managing_organization.first.sub_organization).to eq ['BarBar'] + expect(@obj.complex_instrument.first.managing_organization.first.purpose).to eq ['Managing organization'] + expect(@obj.complex_instrument.first.managing_organization.first.complex_identifier.first.identifier).to eq ['123456789mo'] + expect(@obj.complex_instrument.first.managing_organization.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_instrument.first.title).to eq ['Instrument title'] + end + + it 'creates an complex_instrument active triple resource with date, identifier and person' do + skip + @obj = build(:dataset, + complex_instrument_attributes: [{ + complex_date_attributes: [{ + date: ['2018-01-28'], + }], + complex_identifier_attributes: [{ + identifier: ['ewfqwefqwef'], + }], + complex_person_attributes: [{ + name: ['operator 1'], + role: ['Operator'] + }] + }] + ) + expect(@obj.complex_instrument.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.complex_date.first.date).to eq ['2018-01-28'] + expect(@obj.complex_instrument.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.complex_identifier.first.identifier).to eq ['ewfqwefqwef'] + expect(@obj.complex_instrument.first.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_instrument.first.complex_person.first.name).to eq ['operator 1'] + expect(@obj.complex_instrument.first.complex_person.first.role).to eq ['Operator'] + end + + it 'rejects an complex_instrument active triple with no date, identifier and person' do + skip + @obj = build(:dataset, complex_instrument_attributes: [{ + title: 'Instrument A', + }] + ) + expect(@obj.complex_instrument).to be_empty + end + end + + describe 'origin_system_provenance' do + it 'has origin_system_provenance' do + @obj = build(:dataset, origin_system_provenance: 'origin system provenance') + expect(@obj.origin_system_provenance).to eq 'origin system provenance' + end + end + + describe 'properties_addressed' do + it 'has properties_addressed' do + @obj = build(:dataset, properties_addressed: ['properties addressed']) + expect(@obj.properties_addressed).to eq ['properties addressed'] + end + end + + describe 'complex_relation' do + it 'creates a relation active triple resource with all the attributes' do + @obj = build(:dataset, + complex_relation_attributes: [{ + title: 'A related item', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['123456'], + label: ['local'] + }], + relationship: 'IsPartOf' + }] + ) + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to eq ['A related item'] + expect(@obj.complex_relation.first.url).to eq ['http://example.com/relation'] + expect(@obj.complex_relation.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_relation.first.complex_identifier.first.label).to eq ['local'] + expect(@obj.complex_relation.first.relationship).to eq ['IsPartOf'] + end + + it 'creates a relation active triple resource with title, url, identifier and relationship role' do + @obj = build(:dataset, + complex_relation_attributes: [{ + title: 'A relation label', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ + identifier: ['123456'] + }], + relationship: 'isNewVersionOf' + }] + ) + expect(@obj.complex_relation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.title).to eq ['A relation label'] + expect(@obj.complex_relation.first.url).to eq ['http://example.com/relation'] + expect(@obj.complex_relation.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_relation.first.complex_identifier.first.identifier).to eq ['123456'] + expect(@obj.complex_relation.first.complex_identifier.first.label).to be_empty + expect(@obj.complex_relation.first.relationship).to eq ['isNewVersionOf'] + end + + it 'rejects relation active triple with url' do + @obj = build(:dataset, complex_relation_attributes: [{ + url: 'http://example.com/relation' + }] + ) + expect(@obj.complex_relation).to be_empty + end + + it 'rejects relation active triple with identifier' do + @obj = build(:dataset, + complex_relation_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['123456'], + label: 'Local' + }], + }] + ) + expect(@obj.complex_relation).to be_empty + end + + it 'rejects relation active triple with reltionship name' do + @obj = build(:dataset, complex_relation_attributes: [{ + relationship: 'isPartOf' + }] + ) + expect(@obj.complex_relation).to be_empty + end + end + + describe 'specimen_set' do + it 'has specimen_set' do + @obj = build(:dataset, specimen_set: 'Specimen') + expect(@obj.specimen_set).to eq 'Specimen' + end + end + + describe 'specimen_type' do + it 'creates a specimen type active triple resource with all the attributes' do + @obj = build(:dataset, :with_complex_specimen_type) + expect(@obj.complex_specimen_type.first).to be_kind_of ActiveTriples::Resource + # chemical composition + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.id).to include('#chemical_composition') + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.description).to eq ['chemical composition 1'] + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier.first.identifier).to eq ['chemical_composition/1234567'] + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier.first.label).to eq ['Identifier - Persistent'] + # crystallographic structure + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.id).to include('#crystallographic_structure') + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.description).to eq ['crystallographic_structure 1'] + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier.first.identifier).to eq ['crystallographic_structure/123456'] + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier.first.label).to eq ['Local'] + # description + expect(@obj.complex_specimen_type.first.description).to eq ['Specimen description'] + # identifier + expect(@obj.complex_specimen_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_identifier.first.id).to include('#identifier') + expect(@obj.complex_specimen_type.first.complex_identifier.first.identifier).to eq ['specimen/1234567'] + # material type + expect(@obj.complex_specimen_type.first.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_material_type.first.id).to include('#material_type') + expect(@obj.complex_specimen_type.first.complex_material_type.first.description).to eq ['material description'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_type).to eq ['some material type'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_sub_type).to eq ['some other material sub type'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier.first.identifier).to eq ['material/ewfqwefqwef'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier.first.label).to eq ['Identifier - Persistent'] + # purchase record + expect(@obj.complex_specimen_type.first.complex_purchase_record.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.id).to include('#purchase_record') + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.date).to eq ['2018-02-14'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.complex_identifier.first.identifier).to eq ['purchase_record/123456'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.complex_identifier.first.label).to eq ['Identifier - Persistent'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.organization).to eq ['Fooss'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.sub_organization).to eq ['Barss'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.purpose).to eq ['Supplier'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.complex_identifier.first.identifier).to eq ['supplier/123456789'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.supplier.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.organization).to eq ['Foo'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.sub_organization).to eq ['Bar'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.purpose).to eq ['Manufacturer'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.complex_identifier.first.identifier).to eq ['manufacturer/123456789'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.manufacturer.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.purchase_record_item).to eq ['Has a purchase record item'] + expect(@obj.complex_specimen_type.first.complex_purchase_record.first.title).to eq ['Purchase record title'] + # shape + expect(@obj.complex_specimen_type.first.complex_shape.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_shape.first.id).to include('#shape') + expect(@obj.complex_specimen_type.first.complex_shape.first.description).to eq ['shape description'] + expect(@obj.complex_specimen_type.first.complex_shape.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_shape.first.complex_identifier.first.identifier).to eq ['shape/123456'] + expect(@obj.complex_specimen_type.first.complex_shape.first.complex_identifier.first.label).to eq ['Identifier - Persistent'] + # state of matter + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.id).to include('#state_of_matter') + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.description).to eq ['state of matter description'] + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.complex_identifier.first.identifier).to eq ['state/123456'] + expect(@obj.complex_specimen_type.first.complex_state_of_matter.first.complex_identifier.first.label).to eq ["Identifier - Persistent"] + # structural feature + expect(@obj.complex_specimen_type.first.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.id).to include('#structural_feature') + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.description).to eq ['structural feature description'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.category).to eq ['structural feature category'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.sub_category).to eq ['structural feature sub category'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier.first.identifier).to eq ['structural_feature/123456'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier.first.label).to eq ["Identifier - Persistent"] + # title + expect(@obj.complex_specimen_type.first.title).to eq ['Specimen 1'] + end + + it 'creates a specimen type active triple resource with the 7 required attributes' do + @obj = build(:dataset, + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + description: 'material description' + }], + complex_structural_feature_attributes: [{ + description: 'structural feature description' + }], + title: 'Specimen 1' + }] + ) + # chemical composition + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.id).to include('#chemical_composition') + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.description).to eq ['chemical composition 1'] + expect(@obj.complex_specimen_type.first.complex_chemical_composition.first.complex_identifier).to be_empty + # crystallographic structure + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.id).to include('#crystallographic_structure') + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.description).to eq ['crystallographic_structure 1'] + expect(@obj.complex_specimen_type.first.complex_crystallographic_structure.first.complex_identifier).to be_empty + # description + expect(@obj.complex_specimen_type.first.description).to eq ['Specimen description'] + # identifier + expect(@obj.complex_specimen_type.first.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_identifier.first.id).to include('#identifier') + expect(@obj.complex_specimen_type.first.complex_identifier.first.identifier).to eq ['specimen/1234567'] + # material type + expect(@obj.complex_specimen_type.first.complex_material_type.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_material_type.first.id).to include('#material_type') + expect(@obj.complex_specimen_type.first.complex_material_type.first.description).to eq ['material description'] + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_type).to be_empty + expect(@obj.complex_specimen_type.first.complex_material_type.first.material_sub_type).to be_empty + expect(@obj.complex_specimen_type.first.complex_material_type.first.complex_identifier).to be_empty + # purchase record + expect(@obj.complex_specimen_type.first.complex_purchase_record).to be_empty + # shape + expect(@obj.complex_specimen_type.first.complex_shape).to be_empty + # state of matter + expect(@obj.complex_specimen_type.first.complex_state_of_matter).to be_empty + # structural feature + expect(@obj.complex_specimen_type.first.complex_structural_feature.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.id).to include('#structural_feature') + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.description).to eq ['structural feature description'] + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.category).to be_empty + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.sub_category).to be_empty + expect(@obj.complex_specimen_type.first.complex_structural_feature.first.complex_identifier).to be_empty + # title + expect(@obj.complex_specimen_type.first.title).to eq ['Specimen 1'] + end + + it 'rejects a specimen type active triple with no identifier' do + skip + @obj = build(:dataset, + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + description: 'chemical composition 1', + }], + complex_crystallographic_structure_attributes: [{ + description: 'crystallographic_structure 1', + }], + description: 'Specimen description', + complex_material_type_attributes: [{ + material_sub_type: 'some sub material type', + }], + complex_structural_feature_attributes: [{ + sub_category: 'structural feature sub category', + }], + title: 'Specimen 1' + }] + ) + expect(@obj.complex_specimen_type).to be_empty + end + + it 'rejects a specimen type active triple with some required and some non-required information' do + skip + @obj = build(:dataset, + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ + complex_identifier_attributes: [{ + identifier: 'chemical_composition/1234567' + }], + }], + complex_crystallographic_structure_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['crystallographic_structure/123456'], + label: ['Local'] + }], + }], + description: 'Specimen description', + complex_identifier_attributes: [{ + identifier: 'specimen/1234567' + }], + complex_material_type_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['material/ewfqwefqwef'], + label: ['Local'] + }], + }], + complex_purchase_record_attributes: [{ + date: ['2018-02-14'], + complex_identifier_attributes: [{ + identifier: ['purchase_record/123456'], + label: ['Local'] + }], + supplier_attributes: [{ + organization: 'Fooss', + sub_organization: 'Barss', + purpose: 'Supplier', + }], + manufacturer_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'Manufacturer', + }], + purchase_record_item: ['Has a purchase record item'], + title: 'Purchase record title' + }], + complex_shape_attributes: [{ + description: 'shape description', + }], + complex_state_of_matter_attributes: [{ + description: 'state of matter description', + }], + complex_structural_feature_attributes: [{ + complex_identifier_attributes: [{ + identifier: ['structural_feature/123456'], + label: ['Local'] + }] + }], + title: 'Specimen 1' + }] + ) + expect(@obj.complex_specimen_type).to be_empty + end + end + + describe 'synthesis_and_processing' do + it 'has synthesis_and_processing' do + @obj = build(:dataset, synthesis_and_processing: ['Synthesis and processing methods']) + expect(@obj.synthesis_and_processing).to eq ['Synthesis and processing methods'] + end + end + + describe 'custom_property' do + it 'creates a custom property (additional metadata) active triple resource with all the attributes' do + @obj = build(:dataset, + custom_property_attributes: [{ + label: 'Full name', + description: 'My full name is ...' + }] + ) + expect(@obj.custom_property.first).to be_kind_of ActiveTriples::Resource + expect(@obj.custom_property.first.id).to include('#key_value') + expect(@obj.custom_property.first.label).to eq ['Full name'] + expect(@obj.custom_property.first.description).to eq ['My full name is ...'] + end + + it 'rejects a custom property (additional metadata) active triple with no label' do + @obj = build(:dataset, + custom_property_attributes: [{ + description: 'Local date' + }] + ) + expect(@obj.custom_property).to be_empty + end + + it 'rejects a custom property (additional metadata) active triple with no description' do + @obj = build(:dataset, + custom_property_attributes: [{ + label: 'Local date' + }] + ) + expect(@obj.custom_property).to be_empty + end + end + + describe 'complex_identifier' do + it 'creates an identifier active triple resource with all the attributes' do + @obj = build(:dataset, + complex_identifier_attributes: [{ + identifier: '0000-0000-0000-0000', + scheme: 'uri_of_ORCID_scheme', + label: 'ORCID' + }] + ) + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['0000-0000-0000-0000'] + expect(@obj.complex_identifier.first.scheme).to eq ['uri_of_ORCID_scheme'] + expect(@obj.complex_identifier.first.label).to eq ['ORCID'] + end + + it 'creates an identifier active triple resource with just the identifier' do + @obj = build(:publication, + complex_identifier_attributes: [{ + identifier: '1234' + }] + ) + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['1234'] + expect(@obj.complex_identifier.first.label).to be_empty + expect(@obj.complex_identifier.first.scheme).to be_empty + end + + it 'rejects an identifier active triple with no identifier' do + @obj = build(:publication, + complex_identifier_attributes: [{ + label: 'Local' + }] + ) + expect(@obj.complex_identifier).to be_empty + end + end +end diff --git a/hyrax/spec/models/doi_spec.rb b/hyrax/spec/models/doi_spec.rb new file mode 100644 index 00000000..0c1bea2a --- /dev/null +++ b/hyrax/spec/models/doi_spec.rb @@ -0,0 +1,71 @@ +require 'rails_helper' + +RSpec.describe DOI do + let(:doi) { described_class.new(value) } + + shared_examples 'doi' do + context 'url' do + subject { doi.url } + it { is_expected.to eql('https://doi.org/10.5555/12345678') } + end + + context 'label' do + subject { doi.label } + it { is_expected.to eql('doi:10.5555/12345678') } + end + + context 'identifier' do + subject { doi.identifier } + it { is_expected.to eql('10.5555/12345678') } + end + end + + context 'http:// prefix' do + context 'with dx.' do + let(:value) { 'http://dx.doi.org/10.5555/12345678' } + it_behaves_like 'doi' + end + context 'without dx.' do + let(:value) { 'http://doi.org/10.5555/12345678' } + it_behaves_like 'doi' + end + end + + context 'https:// prefix' do + context 'with dx.' do + let(:value) { 'https://dx.doi.org/10.5555/12345678' } + it_behaves_like 'doi' + end + context 'without dx.' do + let(:value) { 'https://doi.org/10.5555/12345678' } + it_behaves_like 'doi' + end + end + + context 'doi: prefix' do + context 'with whitespace' do + let(:value) { 'doi: 10.5555/12345678' } + it_behaves_like 'doi' + end + context 'without whitespace' do + let(:value) { 'doi:10.5555/12345678' } + it_behaves_like 'doi' + end + end + + context 'info:doi/ prefix' do + context 'with whitespace' do + let(:value) { 'info: doi/10.5555/12345678' } + it_behaves_like 'doi' + end + context 'without whitespace' do + let(:value) { 'info:doi/10.5555/12345678' } + it_behaves_like 'doi' + end + end + + context 'no prefix' do + let(:value) { '10.5555/12345678' } + it_behaves_like 'doi' + end +end diff --git a/hyrax/spec/models/file_set_spec.rb b/hyrax/spec/models/file_set_spec.rb index 7198576a..5d0647e7 100644 --- a/hyrax/spec/models/file_set_spec.rb +++ b/hyrax/spec/models/file_set_spec.rb @@ -1,7 +1,13 @@ require 'rails_helper' RSpec.describe FileSet do - it "has tests" do - skip "Add your tests here" + it "adds plain text to office_document_mime_types" do + expect(described_class.office_document_mime_types).to include('text/plain') + end + it "adds csv to office_document_mime_types" do + expect(described_class.office_document_mime_types).to include('text/csv') + end + it "adds tsv to office_document_mime_types" do + expect(described_class.office_document_mime_types).to include('text/tab-separated-values') end end diff --git a/hyrax/spec/models/handle_spec.rb b/hyrax/spec/models/handle_spec.rb new file mode 100644 index 00000000..6ae629ff --- /dev/null +++ b/hyrax/spec/models/handle_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' + +RSpec.describe Handle do + let(:handle) { described_class.new(value) } + + shared_examples 'handle' do + context 'url' do + subject { handle.url } + it { is_expected.to eql('https://hdl.handle.net/4263537/400') } + end + + context 'label' do + subject { handle.label } + it { is_expected.to eql('hdl:4263537/400') } + end + + context 'identifier' do + subject { handle.identifier } + it { is_expected.to eql('4263537/400') } + end + end + + context 'http:// prefix' do + let(:value) { 'http://hdl.handle.net/4263537/400' } + it_behaves_like 'handle' + end + + context 'https:// prefix' do + let(:value) { 'https://hdl.handle.net/4263537/400' } + it_behaves_like 'handle' + end + + context 'hdl: prefix' do + context 'with whitespace' do + let(:value) { 'hdl: 4263537/400' } + it_behaves_like 'handle' + end + context 'without whitespace' do + let(:value) { 'hdl:4263537/400' } + it_behaves_like 'handle' + end + end + + context 'info:hdl/ prefix' do + context 'with whitespace' do + let(:value) { 'info: hdl/4263537/400' } + it_behaves_like 'handle' + end + context 'without whitespace' do + let(:value) { 'info:hdl/4263537/400' } + it_behaves_like 'handle' + end + end + + context 'no prefix' do + let(:value) { '4263537/400' } + it_behaves_like 'handle' + end +end diff --git a/hyrax/spec/models/image_spec.rb b/hyrax/spec/models/image_spec.rb new file mode 100644 index 00000000..1ad82657 --- /dev/null +++ b/hyrax/spec/models/image_spec.rb @@ -0,0 +1,395 @@ +# Generated via +# `rails generate hyrax:work Image` +require 'rails_helper' + +RSpec.describe Image do + it 'has human readable type for the image' do + @obj = build(:image) + expect(@obj.human_readable_type).to eq('Image') + end + + describe 'date_modified' do + it 'has date_modified as singular' do + @obj = build(:image, date_modified: '2018/04/23') + expect(@obj.date_modified).to eq '2018/04/23' + end + end + + describe 'date_uploaded' do + it 'has date_uploaded as singular' do + @obj = build(:image, date_uploaded: '2018 01 02') + expect(@obj.date_uploaded).to eq '2018 01 02' + end + end + + describe 'depositor' do + it 'has depositor' do + @obj = build(:image, depositor: 'Name of depositor') + expect(@obj.depositor).to eq 'Name of depositor' + end + end + + describe 'title' do + it 'requires title' do + @obj = build(:image, title: nil) + expect{@obj.save!}.to raise_error(ActiveFedora::RecordInvalid, + 'Validation failed: Title Your image must have a title.') + end + + it 'has a multi valued title field' do + @obj = build(:image, title: ['test dataset']) + expect(@obj.title).to eq ['test dataset'] + end + end + + describe 'based_near' do + it 'has based_near' do + @obj = build(:image, based_near: ['me']) + expect(@obj.based_near).to eq ['me'] + end + end + + describe 'bibliographic_citation' do + it 'has bibliographic_citation' do + @obj = build(:image, bibliographic_citation: ['bibliographic_citation 1']) + expect(@obj.bibliographic_citation).to eq ['bibliographic_citation 1'] + end + end + + describe 'contributor' do + it 'has contributor' do + @obj = build(:image, contributor: ['contributor 1']) + expect(@obj.contributor).to eq ['contributor 1'] + end + end + + describe 'creator' do + it 'has creator' do + @obj = build(:image, creator: ['Creator 1']) + expect(@obj.creator).to eq ['Creator 1'] + end + end + + describe 'date_created' do + it 'has date_created' do + @obj = build(:image, date_created: ['date_created 1']) + expect(@obj.date_created).to eq ['date_created 1'] + end + end + + describe 'description' do + it 'has description' do + @obj = build(:image, description: ['description 1']) + expect(@obj.description).to eq ['description 1'] + end + end + + describe 'identifier' do + it 'has identifier' do + @obj = build(:image, identifier: ['identifier 1']) + expect(@obj.identifier).to eq ['identifier 1'] + end + end + + describe 'import_url' do + it 'has import_url as singular' do + @obj = build(:image, import_url: 'http://example.com/import/url') + expect(@obj.import_url).to eq 'http://example.com/import/url' + end + end + + describe 'keyword' do + it 'has keyword' do + @obj = build(:image, keyword: ['keyword 1', 'keyword 2']) + expect(@obj.keyword).to eq ['keyword 1', 'keyword 2'] + end + end + + describe 'label' do + it 'has label as singular' do + @obj = build(:image, label: 'Label 1') + expect(@obj.label).to eq 'Label 1' + end + end + + describe 'language' do + it 'has language' do + @obj = build(:image, language: ['language 1']) + expect(@obj.language).to eq ['language 1'] + end + end + + describe 'part_of' do + it 'has part_of' do + skip 'Not using this field. Raises RSolr::Error::ConnectionRefused when added to index.' + @obj = build(:image, part_of: ['Bigger image']) + expect(@obj.part_of).to eq ['Bigger image'] + end + end + + describe 'publisher' do + it 'has publisher' do + @obj = build(:image, publisher: ['publisher 1']) + expect(@obj.publisher).to eq ['publisher 1'] + end + end + + describe 'related_url' do + it 'has related_url' do + @obj = build(:image, related_url: ['http://example.com/related/url']) + expect(@obj.related_url).to eq ['http://example.com/related/url'] + end + end + + describe 'relative_path' do + it 'has relative_path as singular' do + @obj = build(:image, relative_path: 'relative/path/to/file') + expect(@obj.relative_path).to eq 'relative/path/to/file' + end + end + + describe 'resource_type' do + it 'has resource_type' do + @obj = build(:image, resource_type: ['Dataset']) + expect(@obj.resource_type).to eq ['Dataset'] + end + end + + describe 'rights or license' do + it 'has license (saved as dct:rights)' do + @obj = build(:image, license: ['CC-0']) + expect(@obj.license).to eq ['CC-0'] + end + end + + describe 'complex_rights' do + it 'creates a complex rights active triple resource with rights' do + @obj = build(:image, complex_rights_attributes: [{rights: 'cc0'}]) + expect(@obj.complex_rights.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_rights.first.id).to include('#rights') + expect(@obj.complex_rights.first.rights).to eq ['cc0'] + expect(@obj.complex_rights.first.date).to be_empty + end + + it 'creates a rights active triple resource with all the attributes' do + @obj = build(:image, complex_rights_attributes: [{ + date: '1978-10-28', + rights: 'CC0' + }] + ) + expect(@obj.complex_rights.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_rights.first.date).to eq ['1978-10-28'] + expect(@obj.complex_rights.first.rights).to eq ['CC0'] + end + + it 'rejects a rights active triple with no rights' do + @obj = build(:image, complex_rights_attributes: [{ + date: '2018-01-01' + }] + ) + expect(@obj.complex_rights).to be_empty + end + end + + describe 'rights_statement' do + it 'has rights_statement' do + @obj = build(:image, rights_statement: ['rights_statement 1']) + expect(@obj.rights_statement).to eq ['rights_statement 1'] + end + end + + describe 'source' do + it 'has source' do + @obj = build(:image, source: ['Source 1']) + expect(@obj.source).to eq ['Source 1'] + end + end + + describe 'subject' do + it 'has subject' do + @obj = build(:image, subject: ['subject 1']) + expect(@obj.subject).to eq ['subject 1'] + end + end + + describe 'alternative_title' do + it 'has alternative_title as singular' do + @obj = build(:image, alternative_title: 'Alternative Title') + expect(@obj.alternative_title).to eq 'Alternative Title' + end + end + + describe 'complex_date' do + it 'creates a date active triple resource with all the attributes' do + @obj = build(:image, complex_date_attributes: [ + { + date: '1978-10-28', + description: 'Some kind of a date', + } + ]) + expect(@obj.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_date.first.date).to eq ['1978-10-28'] + expect(@obj.complex_date.first.description).to eq ['Some kind of a date'] + end + + it 'creates a date active triple resource with just the date' do + @obj = build(:image, + complex_date_attributes: [{ + date: '1984-09-01' + }] + ) + expect(@obj.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_date.first.date).to eq ['1984-09-01'] + expect(@obj.complex_date.first.description).to be_empty + end + + it 'rejects a date active triple with no date' do + @obj = build(:image, + complex_date_attributes: [{ + description: 'Local date' + }] + ) + expect(@obj.complex_date).to be_empty + end + end + + describe 'complex_identifier' do + it 'creates an identifier active triple resource with all the attributes' do + @obj = build(:image, complex_identifier_attributes: [ + { + identifier: '0000-0000-0000-0000', + scheme: 'uri_of_ORCID_scheme', + label: 'ORCID' + }] + ) + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['0000-0000-0000-0000'] + expect(@obj.complex_identifier.first.scheme).to eq ['uri_of_ORCID_scheme'] + expect(@obj.complex_identifier.first.label).to eq ['ORCID'] + end + + it 'creates an identifier active triple resource with just the identifier' do + @obj = build(:image, complex_identifier_attributes: [{ + identifier: '1234' + }] + ) + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['1234'] + expect(@obj.complex_identifier.first.label).to be_empty + expect(@obj.complex_identifier.first.scheme).to be_empty + end + + it 'rejects an identifier active triple with no identifier' do + @obj = build(:image, complex_identifier_attributes: [{ + label: 'Local' + }] + ) + expect(@obj.complex_identifier).to be_empty + end + end + + describe 'complex_person' do + it 'creates a person active triple resource with name' do + @obj = build(:image, complex_person_attributes: [{ + name: 'Anamika' + }] + ) + expect(@obj.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.name).to eq ['Anamika'] + expect(@obj.complex_person.first.first_name).to be_empty + expect(@obj.complex_person.first.last_name).to be_empty + expect(@obj.complex_person.first.complex_affiliation).to be_empty + expect(@obj.complex_person.first.role).to be_empty + expect(@obj.complex_person.first.complex_identifier).to be_empty + expect(@obj.complex_person.first.uri).to be_empty + end + + it 'creates a person active triple resource with name, affiliation and role' do + @obj = build(:image, complex_person_attributes: [{ + name: 'Anamika', + complex_affiliation_attributes: [{ + job_title: 'Master', + complex_organization_attributes: [{ + organization: 'Org', + sub_organization: 'Sub org', + purpose: 'org purpose', + }] + }], + role: 'Creator' + }] + ) + expect(@obj.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.name).to eq ['Anamika'] + expect(@obj.complex_person.first.first_name).to be_empty + expect(@obj.complex_person.first.last_name).to be_empty + expect(@obj.complex_person.first.complex_affiliation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.complex_affiliation.first.job_title).to eq ['Master'] + expect(@obj.complex_person.first.complex_affiliation.first.complex_organization.first.organization).to eq ['Org'] + expect(@obj.complex_person.first.complex_affiliation.first.complex_organization.first.sub_organization).to eq ['Sub org'] + expect(@obj.complex_person.first.complex_affiliation.first.complex_organization.first.purpose).to eq ['org purpose'] + expect(@obj.complex_person.first.complex_affiliation.first.complex_organization.first.complex_identifier).to be_empty + expect(@obj.complex_person.first.role).to eq ['Creator'] + expect(@obj.complex_person.first.complex_identifier).to be_empty + expect(@obj.complex_person.first.uri).to be_empty + end + + it 'rejects person active triple with no name and only uri' do + @obj = build(:image, complex_person_attributes: [{ + uri: 'http://example.com/person/123456'}] + ) + expect(@obj.complex_person).to be_empty + end + end + + describe 'complex_version' do + it 'creates a version active triple resource with all the attributes' do + @obj = build(:image, + complex_version_attributes: [{ + date: '1978-10-28', + description: 'Creating the first version', + identifier: 'id1', + version: '1.0' + }] + ) + expect(@obj.complex_version.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_version.first.id).to include('#version') + expect(@obj.complex_version.first.date).to eq ['1978-10-28'] + expect(@obj.complex_version.first.description).to eq ['Creating the first version'] + expect(@obj.complex_version.first.identifier).to eq ['id1'] + expect(@obj.complex_version.first.version).to eq ['1.0'] + end + + it 'creates a version active triple resource with just the version' do + @obj = build(:image, + complex_version_attributes: [{ + version: '1.0' + }] + ) + expect(@obj.complex_version.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_version.first.id).to include('#version') + expect(@obj.complex_version.first.version).to eq ['1.0'] + expect(@obj.complex_version.first.date).to be_empty + expect(@obj.complex_version.first.description).to be_empty + expect(@obj.complex_version.first.identifier).to be_empty + end + + it 'rejects a version active triple with no version' do + @obj = build(:image, + complex_version_attributes: [{ + description: 'Local version', + identifier: 'id1', + date: '2018-01-01' + }] + ) + expect(@obj.complex_version).to be_empty + end + end + + describe 'ststus' do + it 'has status' do + @obj = build(:image, status: 'Status 1') + expect(@obj.status).to eq 'Status 1' + end + end + +end diff --git a/hyrax/spec/models/publication_spec.rb b/hyrax/spec/models/publication_spec.rb new file mode 100644 index 00000000..7d92ea1d --- /dev/null +++ b/hyrax/spec/models/publication_spec.rb @@ -0,0 +1,550 @@ +# Generated via +# `rails generate hyrax:work Publication` +require 'rails_helper' + + +RSpec.describe Publication do + it 'has human readable type for the publication' do + @obj = build(:publication) + expect(@obj.human_readable_type).to eq('Publication') + end + + describe 'date_modified' do + it 'has date_modified as singular' do + @obj = build(:publication, date_modified: '2018/04/23') + expect(@obj.date_modified).to eq '2018/04/23' + end + end + + describe 'date_uploaded' do + it 'has date_uploaded as singular' do + @obj = build(:publication, date_uploaded: '2018 01 02') + expect(@obj.date_uploaded).to eq '2018 01 02' + end + end + + describe 'depositor' do + it 'has depositor' do + @obj = build(:publication, depositor: 'Name of depositor') + expect(@obj.depositor).to eq 'Name of depositor' + end + end + + describe 'title' do + it 'requires title' do + @obj = build(:publication, title: nil) + expect{@obj.save!}.to raise_error(ActiveFedora::RecordInvalid, 'Validation failed: Title Your publication must have a title.') + end + + it 'has a multi valued title field' do + @obj = build(:publication, title: ['test dataset']) + expect(@obj.title).to eq ['test dataset'] + end + end + + describe 'based_near' do + it 'has based_near' do + @obj = build(:publication, based_near: ['me']) + expect(@obj.based_near).to eq ['me'] + end + end + + describe 'bibliographic_citation' do + it 'has bibliographic_citation' do + @obj = build(:publication, bibliographic_citation: ['bibliographic_citation 1']) + expect(@obj.bibliographic_citation).to eq ['bibliographic_citation 1'] + end + end + + describe 'contributor' do + it 'has contributor' do + @obj = build(:publication, contributor: ['contributor 1']) + expect(@obj.contributor).to eq ['contributor 1'] + end + end + + describe 'creator' do + it 'has creator' do + @obj = build(:publication, creator: ['Creator 1']) + expect(@obj.creator).to eq ['Creator 1'] + end + end + + describe 'date_created' do + it 'has date_created' do + @obj = build(:publication, date_created: ['date_created 1']) + expect(@obj.date_created).to eq ['date_created 1'] + end + end + + describe 'description' do + it 'has description' do + @obj = build(:publication, description: ['description 1']) + expect(@obj.description).to eq ['description 1'] + end + end + + describe 'identifier' do + it 'has identifier' do + @obj = build(:publication, identifier: ['identifier 1']) + expect(@obj.identifier).to eq ['identifier 1'] + end + end + + describe 'import_url' do + it 'has import_url as singular' do + @obj = build(:publication, import_url: 'http://example.com/import/url') + expect(@obj.import_url).to eq 'http://example.com/import/url' + end + end + + describe 'keyword' do + it 'has keyword' do + @obj = build(:publication, keyword: ['keyword 1', 'keyword 2']) + expect(@obj.keyword).to eq ['keyword 1', 'keyword 2'] + end + end + + describe 'label' do + it 'has label as singular' do + @obj = build(:publication, label: 'Label 1') + expect(@obj.label).to eq 'Label 1' + end + end + + describe 'language' do + it 'has language' do + @obj = build(:publication, language: ['language 1']) + expect(@obj.language).to eq ['language 1'] + end + end + + describe 'part_of' do + it 'has part_of' do + skip 'Not using this field. Raises RSolr::Error::ConnectionRefused when added to index.' + @obj = build(:publication, part_of: ['Bigger publication']) + expect(@obj.part_of).to eq ['Bigger publication'] + end + end + + describe 'publisher' do + it 'has publisher' do + @obj = build(:publication, publisher: ['publisher 1']) + expect(@obj.publisher).to eq ['publisher 1'] + end + end + + describe 'related_url' do + it 'has related_url' do + @obj = build(:publication, related_url: ['http://example.com/related/url']) + expect(@obj.related_url).to eq ['http://example.com/related/url'] + end + end + + describe 'relative_path' do + it 'has relative_path as singular' do + @obj = build(:publication, relative_path: 'relative/path/to/file') + expect(@obj.relative_path).to eq 'relative/path/to/file' + end + end + + describe 'resource_type' do + it 'has resource_type' do + @obj = build(:publication, resource_type: ['Dataset']) + expect(@obj.resource_type).to eq ['Dataset'] + end + end + + describe 'rights or license' do + it 'has license (saved as dct:rights)' do + @obj = build(:publication, license: ['CC-0']) + expect(@obj.license).to eq ['CC-0'] + end + end + + describe 'supervisor_approval' do + it 'has supervisor_approval' do + @obj = build(:publication, supervisor_approval: ['Kosuke Tanabe 2019.08.01']) + expect(@obj.supervisor_approval).to eq ['Kosuke Tanabe 2019.08.01'] + end + end + + describe 'complex_rights' do + it 'creates a complex rights active triple resource with rights' do + @obj = build(:publication, complex_rights_attributes: [{ + rights: 'cc0' + }] + ) + expect(@obj.complex_rights.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_rights.first.id).to include('#rights') + expect(@obj.complex_rights.first.rights).to eq ['cc0'] + expect(@obj.complex_rights.first.date).to be_empty + end + + it 'creates a rights active triple resource with all the attributes' do + @obj = build(:publication, complex_rights_attributes: [{ + date: '1978-10-28', + rights: 'CC0' + }] + ) + expect(@obj.complex_rights.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_rights.first.date).to eq ['1978-10-28'] + expect(@obj.complex_rights.first.rights).to eq ['CC0'] + end + + it 'rejects a rights active triple with no rights' do + @obj = build(:publication, complex_rights_attributes: [{ + date: '2018-01-01' + }] + ) + expect(@obj.complex_rights).to be_empty + end + end + + describe 'rights_statement' do + it 'has rights_statement' do + @obj = build(:publication, rights_statement: ['rights_statement 1']) + expect(@obj.rights_statement).to eq ['rights_statement 1'] + end + end + + describe 'source' do + it 'has source' do + @obj = build(:publication, source: ['Source 1']) + expect(@obj.source).to eq ['Source 1'] + end + end + + describe 'subject' do + it 'has subject' do + @obj = build(:publication, subject: ['subject 1']) + expect(@obj.subject).to eq ['subject 1'] + end + end + + describe 'alternative_title' do + it 'has alternative_title as singular' do + @obj = build(:publication, alternative_title: 'Alternative Title') + expect(@obj.alternative_title).to eq 'Alternative Title' + end + end + + describe 'complex_date' do + it 'creates a date active triple resource with all the attributes' do + @obj = build(:publication, complex_date_attributes: [ + { + date: '2019-05-28', + description: 'Published', + } + ]) + expect(@obj.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_date.first.date).to eq ['2019-05-28'] + expect(@obj.complex_date.first.description).to eq ['Published'] + end + + it 'creates a date active triple resource with just the date' do + @obj = build(:publication, complex_date_attributes: [ + { + date: '1984-09-01' + } + ]) + expect(@obj.complex_date.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_date.first.date).to eq ['1984-09-01'] + expect(@obj.complex_date.first.description).to be_empty + end + + it 'rejects a date active triple with no date' do + @obj = build(:publication, complex_date_attributes: [ + { + description: 'Local date' + } + ]) + expect(@obj.complex_date).to be_empty + end + end + + describe 'complex_identifier' do + it 'creates an identifier active triple resource with all the attributes' do + @obj = build(:publication, + complex_identifier_attributes: [{ + identifier: '0000-0000-0000-0000', + scheme: 'uri_of_ORCID_scheme', + label: 'ORCID' + }] + ) + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['0000-0000-0000-0000'] + expect(@obj.complex_identifier.first.scheme).to eq ['uri_of_ORCID_scheme'] + expect(@obj.complex_identifier.first.label).to eq ['ORCID'] + end + + it 'creates an identifier active triple resource with just the identifier' do + @obj = build(:publication, + complex_identifier_attributes: [{ + identifier: '1234' + }] + ) + expect(@obj.complex_identifier.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_identifier.first.identifier).to eq ['1234'] + expect(@obj.complex_identifier.first.label).to be_empty + expect(@obj.complex_identifier.first.scheme).to be_empty + end + + it 'rejects an identifier active triple with no identifier' do + @obj = build(:publication, + complex_identifier_attributes: [{ + label: 'Local' + }] + ) + expect(@obj.complex_identifier).to be_empty + end + end + + describe 'complex_person' do + it 'creates a person active triple resource with name' do + @obj = build(:publication, + complex_person_attributes: [{ + name: 'Anamika' + }] + ) + expect(@obj.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.name).to eq ['Anamika'] + expect(@obj.complex_person.first.first_name).to be_empty + expect(@obj.complex_person.first.last_name).to be_empty + expect(@obj.complex_person.first.complex_affiliation).to be_empty + expect(@obj.complex_person.first.role).to be_empty + expect(@obj.complex_person.first.complex_identifier).to be_empty + expect(@obj.complex_person.first.uri).to be_empty + end + + it 'creates a person active triple resource with name, affiliation and role' do + @obj = build(:publication, complex_person_attributes: [{ + name: 'Anamika', + complex_affiliation_attributes: [{ + job_title: 'Master', + complex_organization_attributes: [{ + organization: 'Org', + sub_organization: 'Sub org', + purpose: 'org purpose', + }] + }], + role: 'Creator' + }] + ) + expect(@obj.complex_person.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.name).to eq ['Anamika'] + expect(@obj.complex_person.first.first_name).to be_empty + expect(@obj.complex_person.first.last_name).to be_empty + expect(@obj.complex_person.first.complex_affiliation.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_person.first.complex_affiliation.first.job_title).to eq ['Master'] + expect(@obj.complex_person.first.complex_affiliation.first.complex_organization.first.organization).to eq ['Org'] + expect(@obj.complex_person.first.complex_affiliation.first.complex_organization.first.sub_organization).to eq ['Sub org'] + expect(@obj.complex_person.first.complex_affiliation.first.complex_organization.first.purpose).to eq ['org purpose'] + expect(@obj.complex_person.first.complex_affiliation.first.complex_organization.first.complex_identifier).to be_empty + expect(@obj.complex_person.first.role).to eq ['Creator'] + expect(@obj.complex_person.first.complex_identifier).to be_empty + expect(@obj.complex_person.first.uri).to be_empty + end + + it 'rejects person active triple with no name and only uri' do + @obj = build(:publication, complex_person_attributes: [{ + uri: 'http://example.com/person/123456' + }] + ) + expect(@obj.complex_person).to be_empty + end + end + + describe 'complex_version' do + it 'creates a version active triple resource with all the attributes' do + @obj = build(:publication, + complex_version_attributes: [{ + date: '1978-10-28', + description: 'Creating the first version', + identifier: 'id1', + version: '1.0' + }] + ) + expect(@obj.complex_version.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_version.first.id).to include('#version') + expect(@obj.complex_version.first.date).to eq ['1978-10-28'] + expect(@obj.complex_version.first.description).to eq ['Creating the first version'] + expect(@obj.complex_version.first.identifier).to eq ['id1'] + expect(@obj.complex_version.first.version).to eq ['1.0'] + end + + it 'creates a version active triple resource with just the version' do + @obj = build(:publication, + complex_version_attributes: [{ + version: '1.0' + }] + ) + expect(@obj.complex_version.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_version.first.id).to include('#version') + expect(@obj.complex_version.first.version).to eq ['1.0'] + expect(@obj.complex_version.first.date).to be_empty + expect(@obj.complex_version.first.description).to be_empty + expect(@obj.complex_version.first.identifier).to be_empty + end + + it 'rejects a version active triple with no version' do + @obj = build(:publication, + complex_version_attributes: [{ + description: 'Local version', + identifier: 'id1', + date: '2018-01-01' + }] + ) + expect(@obj.complex_version).to be_empty + end + end + + describe 'complex_event' do + it 'creates an event active triple resource with all the attributes' do + @obj = build(:publication, complex_event_attributes: [ + { + end_date: '2019-01-01', + invitation_status: true, + place: '221B Baker Street', + start_date: '2018-12-25', + title: 'A Title' + } + ]) + expect(@obj.complex_event.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_event.first.id).to include('#event') + expect(@obj.complex_event.first.end_date).to eq ['2019-01-01'] + expect(@obj.complex_event.first.invitation_status).to eq [true] + expect(@obj.complex_event.first.place).to eq ['221B Baker Street'] + expect(@obj.complex_event.first.start_date).to eq ['2018-12-25'] + expect(@obj.complex_event.first.title).to eq ['A Title'] + end + + it 'creates an event active triple resource with just the title' do + @obj = build(:publication, + complex_event_attributes: [{ + title: 'Some Title' + }] + ) + expect(@obj.complex_event.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_event.first.id).to include('#event') + expect(@obj.complex_event.first.end_date).to be_empty + expect(@obj.complex_event.first.invitation_status).to be_empty + expect(@obj.complex_event.first.place).to be_empty + expect(@obj.complex_event.first.start_date).to be_empty + expect(@obj.complex_event.first.title).to eq ['Some Title'] + end + + it 'rejects an event active triple with no title' do + @obj = build(:publication, + complex_event_attributes: [{ + end_date: '2019-01-01', + invitation_status: true + }] + ) + expect(@obj.complex_event).to be_empty + end + end + + describe 'issue' do + it 'has issue' do + @obj = build(:publication, issue: 'iss_1') + expect(@obj.issue).to eq 'iss_1' + end + end + + describe 'place' do + it 'has place' do + @obj = build(:publication, place: '221B Baker Street') + expect(@obj.place).to eq '221B Baker Street' + end + end + + describe 'table_of_contents' do + it 'has table_of_contents' do + @obj = build(:publication, table_of_contents: "Some long table of text") + expect(@obj.table_of_contents).to eq "Some long table of text" + end + end + + describe 'total_number_of_pages' do + it 'has total_number_of_pages' do + @obj = build(:publication, total_number_of_pages: 1010) + expect(@obj.total_number_of_pages).to eq 1010 + end + end + + describe 'complex_source' do + it 'creates a complex source active triple resource with an id and all properties' do + @obj = build(:publication, + complex_source_attributes: [{ + alternative_title: 'Sub title for journal', + complex_person_attributes: [{ + name: 'AR', + role: 'Editor' + }], + end_page: '12', + complex_identifier_attributes: [{ + identifier: '1234567', + scheme: 'Local' + }], + issue: '34', + sequence_number: '1.2.2', + start_page: '4', + title: 'Test journal', + total_number_of_pages: '8', + volume: '3' + }] + ) + expect(@obj.complex_source.first.id).to include('#source') + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.alternative_title).to eq ['Sub title for journal'] + expect(@obj.complex_source.first.complex_person.first.name).to eq ['AR'] + expect(@obj.complex_source.first.complex_person.first.role).to eq ['Editor'] + expect(@obj.complex_source.first.end_page).to eq ['12'] + expect(@obj.complex_source.first.complex_identifier.first.identifier).to eq ['1234567'] + expect(@obj.complex_source.first.complex_identifier.first.scheme).to eq ['Local'] + expect(@obj.complex_source.first.issue).to eq ['34'] + expect(@obj.complex_source.first.sequence_number).to eq ['1.2.2'] + expect(@obj.complex_source.first.start_page).to eq ['4'] + expect(@obj.complex_source.first.title).to eq ['Test journal'] + expect(@obj.complex_source.first.total_number_of_pages).to eq ['8'] + expect(@obj.complex_source.first.volume).to eq ['3'] + end + + it 'creates a complex source active triple resource with title' do + @obj = build(:publication, + complex_source_attributes: [{ + title: 'Anamika' + }] + ) + expect(@obj.complex_source.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_source.first.title).to eq ['Anamika'] + expect(@obj.complex_source.first.complex_person).to be_empty + expect(@obj.complex_source.first.end_page).to be_empty + expect(@obj.complex_source.first.issue).to be_empty + expect(@obj.complex_source.first.sequence_number).to be_empty + expect(@obj.complex_source.first.start_page).to be_empty + expect(@obj.complex_source.first.total_number_of_pages).to be_empty + expect(@obj.complex_source.first.volume).to be_empty + end + + it 'rejects source active triple with no values ' do + @obj = build(:publication, + complex_source_attributes: [{ + title: '' + }] + ) + expect(@obj.complex_source).to be_empty + end + + it 'rejects source active triple with nil values' do + @obj = build(:publication, + complex_source_attributes: [{ + sequence_number: nil + }] + ) + expect(@obj.complex_source).to be_empty + end + end + +end diff --git a/hyrax/spec/models/qa/file_based_authority_spec.rb b/hyrax/spec/models/qa/file_based_authority_spec.rb new file mode 100644 index 00000000..6621dcd7 --- /dev/null +++ b/hyrax/spec/models/qa/file_based_authority_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +RSpec.describe Qa::Authorities::Local::FileBasedAuthority do + authorities = [ + 'analysis_fields', + 'characterization_methods', + 'computational_methods', + 'data_origin', + 'dates', + 'material_types', + 'measurement_environments', + 'processing_environments', + 'properties_addressed', + 'roles', + 'structural_features', + 'synthesis_and_processing' + ] + + authorities.each do |authority| + describe authority do + before do + @la = Qa::Authorities::Local::FileBasedAuthority.new(authority) + end + it "has vocabulary for #{authority}" do + expect(@la.all).not_to be_nil + expect(@la.all.size).to be > 0 + end + it "can find a term for #{authority} given the id" do + @term = @la.all.first + @term['term'] = @term.delete('label') + expect(@la.find(@term['id'])).to eq (@term) + end + end + end +end diff --git a/hyrax/spec/models/qa_spec.rb b/hyrax/spec/models/qa_spec.rb new file mode 100644 index 00000000..c7ddb52f --- /dev/null +++ b/hyrax/spec/models/qa_spec.rb @@ -0,0 +1,10 @@ +# NB: using spec_helper instead of rails_helper here to avoid the QA gem from overriding the module in this test +require 'spec_helper' +require_relative '../../app/models/qa' + +RSpec.describe Qa do + describe 'table_name_prefix' do + subject { described_class.table_name_prefix } + it { is_expected.to eql 'qa_'} + end +end diff --git a/hyrax/spec/models/search_builder_spec.rb b/hyrax/spec/models/search_builder_spec.rb new file mode 100644 index 00000000..68cf35d7 --- /dev/null +++ b/hyrax/spec/models/search_builder_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ::SearchBuilder do + # nothing to test +end diff --git a/hyrax/spec/models/solr_document_spec.rb b/hyrax/spec/models/solr_document_spec.rb new file mode 100644 index 00000000..9298f762 --- /dev/null +++ b/hyrax/spec/models/solr_document_spec.rb @@ -0,0 +1,338 @@ +require 'rails_helper' + +RSpec.describe SolrDocument do + let(:model) do + build(:dataset, + alternative_title: 'Alternative Title', + complex_date_attributes: [{ date: ['2018-02-14'], description: 'Published Date' }], + complex_identifier_attributes: [{ identifier: ['123456'], label: ['Local'] }], + complex_instrument_attributes: [{ + complex_date_attributes: [{ date: ['2018-01-28'] }], + complex_identifier_attributes: [{ identifier: ['ewfqwefqwef'] }], + complex_person_attributes: [{ name: ['operator 1'] }], + title: 'Instrument 1' + }], + complex_organization_attributes: [{ + organization: 'Foo', + sub_organization: 'Bar', + purpose: 'org purpose' + }], + complex_person_attributes: [{ name: ['Anamika'] }], + complex_rights_attributes: [{ rights: 'cc0' }], + complex_specimen_type_attributes: [{ + complex_chemical_composition_attributes: [{ description: 'chemical composition 1' }] + }], + complex_version_attributes: [{ version: '1.0' }], + characterization_methods: ['Characterization methods'], + computational_methods: ['computational methods'], + data_origin: ['data origin'], + origin_system_provenance: 'Origin A', + properties_addressed: ['Properties Addressed'], + complex_relation_attributes: [{ + title: 'A related item', + url: 'http://example.com/relation', + complex_identifier_attributes: [{ identifier: ['123456'] }], + relationship: 'IsPartOf' + }], + specimen_set: 'Specimen Set', + synthesis_and_processing: ['Synthesis and processing methods'], + custom_property_attributes: [{ label: 'Full name', description: 'My full name is' }] + ) + end + let(:solr_document) { described_class.new(model.to_solr) } + + describe '#alternative_title' do + subject { solr_document.alternative_title } + it { is_expected.to eql ['Alternative Title'] } + end + + describe '#complex_date' do + let(:complex_date) { JSON.parse(solr_document.complex_date).first } + describe 'date' do + subject { complex_date['date'] } + it { is_expected.to eql ['2018-02-14'] } + end + describe 'description' do + subject { complex_date['description'] } + it { is_expected.to eql ['Published Date'] } + end + end + + describe '#complex_identifier' do + let(:complex_identifier) { JSON.parse(solr_document.complex_identifier).first } + describe 'identifier' do + subject { complex_identifier['identifier'] } + it { is_expected.to eql ['123456'] } + end + describe 'label' do + subject { complex_identifier['label'] } + it { is_expected.to eql ['Local'] } + end + end + + describe '#complex_instrument' do + let(:complex_instrument) { JSON.parse(solr_document.complex_instrument).first } + describe 'complex_date' do + subject { complex_instrument['complex_date'].first['date'] } + it { is_expected.to eql ['2018-01-28'] } + end + describe 'complex_identifier' do + subject { complex_instrument['complex_identifier'].first['identifier'] } + it { is_expected.to eql ['ewfqwefqwef'] } + end + describe 'complex_person' do + subject { complex_instrument['complex_person'].first['name'] } + it { is_expected.to eql ['operator 1'] } + end + describe 'title' do + subject { complex_instrument['title'] } + it { is_expected.to eql ['Instrument 1'] } + end + end + + describe '#complex_organization' do + let(:complex_organization) { JSON.parse(solr_document.complex_organization).first } + describe 'organization' do + subject { complex_organization['organization'] } + it { is_expected.to eql ['Foo'] } + end + describe 'sub_organization' do + subject { complex_organization['sub_organization'] } + it { is_expected.to eql ['Bar'] } + end + describe 'purpose' do + subject { complex_organization['purpose'] } + it { is_expected.to eql ['org purpose'] } + end + end + + describe '#complex_person' do + let(:complex_person) { JSON.parse(solr_document.complex_person).first } + describe 'name' do + subject { complex_person['name'] } + it { is_expected.to eql ['Anamika'] } + end + end + + describe '#complex_rights' do + let(:complex_rights) { JSON.parse(solr_document.complex_rights).first } + subject { complex_rights['rights'] } + it { is_expected.to eql ['cc0'] } + end + + describe '#complex_specimen_type' do + let(:complex_specimen_type) { JSON.parse(solr_document.complex_specimen_type).first } + describe 'complex_chemical_composition' do + subject { complex_specimen_type['complex_chemical_composition'].first['description'] } + it { is_expected.to eql ['chemical composition 1'] } + end + end + + describe '#complex_version' do + let(:complex_version) { JSON.parse(solr_document.complex_version).first } + subject { complex_version['version'] } + it { is_expected.to eql ['1.0'] } + end + + describe '#characterization_methods' do + subject { solr_document.characterization_methods } + it { is_expected.to eql ['Characterization methods'] } + end + + describe '#computational_methods' do + subject { solr_document.computational_methods } + it { is_expected.to eql ['computational methods'] } + end + + describe '#data_origin' do + subject { solr_document.data_origin } + it { is_expected.to eql ['data origin'] } + end + + describe '#instrument' do + let(:model) { build(:image, instrument: ['Instrument']) } + subject { solr_document.instrument } + it { is_expected.to eql ['Instrument'] } + end + + describe '#origin_system_provenance' do + subject { solr_document.origin_system_provenance } + it { is_expected.to eql ['Origin A'] } + end + + describe '#properties_addressed' do + subject { solr_document.properties_addressed } + it { is_expected.to eql ['Properties Addressed'] } + end + + describe '#complex_relation' do + let(:complex_relation) { JSON.parse(solr_document.complex_relation).first } + describe 'title' do + subject { complex_relation['title'] } + it { is_expected.to eql ['A related item'] } + end + describe 'url' do + subject { complex_relation['url'] } + it { is_expected.to eql ['http://example.com/relation'] } + end + describe 'complex_identifier' do + subject { complex_relation['complex_identifier'].first['identifier'] } + it { is_expected.to eql ['123456'] } + end + describe 'relationship' do + subject { complex_relation['relationship'] } + it { is_expected.to eql ['IsPartOf'] } + end + end + + describe '#specimen_set' do + subject { solr_document.specimen_set } + it { is_expected.to eql ['Specimen Set'] } + end + + describe '#synthesis_and_processing' do + subject { solr_document.synthesis_and_processing } + it { is_expected.to eql ['Synthesis and processing methods'] } + end + + describe '#custom_property' do + let(:custom_property) { JSON.parse(solr_document.custom_property).first } + describe 'label' do + subject { custom_property['label'] } + it { is_expected.to eql ['Full name'] } + end + describe 'description' do + subject { custom_property['description'] } + it { is_expected.to eql ['My full name is'] } + end + end + + describe '#complex_event' do + let(:model) { build(:publication, + complex_event_attributes: [{ + end_date: '2019-01-01', + invitation_status: true, + place: '221B Baker Street', + start_date: '2018-12-25', + title: 'A Title' + }] + )} + let(:complex_event) { JSON.parse(solr_document.complex_event).first } + describe 'end_date' do + subject { complex_event['end_date'] } + it { is_expected.to eql ['2019-01-01'] } + end + describe 'invitation_status' do + subject { complex_event['invitation_status'] } + it { is_expected.to eql [true] } + end + describe 'place' do + subject { complex_event['place'] } + it { is_expected.to eql ['221B Baker Street'] } + end + describe 'start_date' do + subject { complex_event['start_date'] } + it { is_expected.to eql ['2018-12-25'] } + end + describe 'title' do + subject { complex_event['title'] } + it { is_expected.to eql ['A Title'] } + end + end + + describe '#issue' do + let(:model) { build(:publication, issue: 'iss_1') } + subject { solr_document.issue } + it { is_expected.to eql ['iss_1'] } + end + + describe '#place' do + let(:model) { build(:publication, place: '221B Baker Street') } + subject { solr_document.place } + it { is_expected.to eql ['221B Baker Street'] } + end + + describe '#table_of_contents' do + let(:model) { build(:publication, table_of_contents: 'Contents A') } + subject { solr_document.table_of_contents } + it { is_expected.to eql ['Contents A'] } + end + + describe '#total_number_of_pages' do + let(:model) { build(:publication, total_number_of_pages: '12') } + subject { solr_document.total_number_of_pages } + it { is_expected.to eql ['12'] } + end + + describe '#complex_source' do + let(:model) { build(:publication, + complex_source_attributes: [{ + alternative_title: 'Sub title for journal', + end_page: '12', + issue: '34', + sequence_number: '1.2.2', + start_page: '4', + title: 'Test journal', + total_number_of_pages: '8', + volume: '3' + }] + )} + let(:complex_source) { JSON.parse(solr_document.complex_source).first } + describe 'alternative_title' do + subject { complex_source['alternative_title'] } + it { is_expected.to eql ['Sub title for journal'] } + end + describe 'end_page' do + subject { complex_source['end_page'] } + it { is_expected.to eql ['12'] } + end + describe 'issue' do + subject { complex_source['issue'] } + it { is_expected.to eql ['34'] } + end + describe 'sequence_number' do + subject { complex_source['sequence_number'] } + it { is_expected.to eql ['1.2.2'] } + end + describe 'start_page' do + subject { complex_source['start_page'] } + it { is_expected.to eql ['4'] } + end + describe 'title' do + subject { complex_source['title'] } + it { is_expected.to eql ['Test journal'] } + end + describe 'total_number_of_pages' do + subject { complex_source['total_number_of_pages'] } + it { is_expected.to eql ['8'] } + end + describe 'volume' do + subject { complex_source['volume'] } + it { is_expected.to eql ['3'] } + end + end + + describe '#status' do + let(:model) { build(:image, status: 'Status') } + subject { solr_document.status } + it { is_expected.to eql ['Status'] } + end + + describe '#persistent_url (Dataset)' do + let(:model) { build(:dataset, id: '123456', title: ['Test']) } + subject { solr_document.persistent_url } + it { is_expected.to eql "http://localhost/concern/datasets/#{solr_document.id}" } + end + + describe '#persistent_url (Image)' do + let(:model) { build(:image, id: '123456', title: ['Test']) } + subject { solr_document.persistent_url } + it { is_expected.to eql "http://localhost/concern/images/#{solr_document.id}" } + end + + describe '#persistent_url (Publication)' do + let(:model) { build(:publication, id: '123456', title: ['Test']) } + subject { solr_document.persistent_url } + it { is_expected.to eql "http://localhost/concern/publications/#{solr_document.id}" } + end +end diff --git a/hyrax/spec/models/user_spec.rb b/hyrax/spec/models/user_spec.rb new file mode 100644 index 00000000..d8b5528e --- /dev/null +++ b/hyrax/spec/models/user_spec.rb @@ -0,0 +1,146 @@ +require 'rails_helper' + +RSpec.describe ::User do + let(:user) { described_class.new(username: 'username', display_name: 'Test user') } + + describe '#to_s' do + subject { user.to_s } + it { is_expected.to eql 'Test user'} + end + + describe '#ldap_before_save' do + before do + allow(Devise::LDAP::Adapter).to receive(:get_ldap_param).with(user.username, 'mail') { ['email@example.com'] } + allow(Devise).to receive(:friendly_token) { 'password' } + user.ldap_before_save + end + + it 'gets the email from ldap' do + expect(user.email).to eql('email@example.com') + end + + it 'generates a password' do + expect(user.password).to eql('password') + end + end + + describe 'self.find_or_create_system_user' do + let!(:existing_user) { create(:user, email: 'existing@example.com') } + before { allow(Devise).to receive(:friendly_token) { 'password' } } + + context 'finds the existing user' do + subject { described_class.find_or_create_system_user('existing@example.com') } + it { is_expected.to eql existing_user} + end + + context 'creates a new user' do + subject { described_class.find_or_create_system_user('new@example.com') } + it { is_expected.to_not eql existing_user} + + it 'sets the username' do + expect(subject.username).to eql 'new' + end + + it 'sets the email' do + expect(subject.email).to eql 'new@example.com' + end + + it 'sets the password' do + expect(subject.password).to eql 'password' + end + end + end + + describe 'NIMS Roles' do + let(:user) { described_class.new(employee_type_code: employee_type_code) } + + describe '#authenticated_nims_researcher?' do + subject { user.authenticated_nims_researcher? } + + context 'employee_type A' do + let(:employee_type_code) { 'A' } + it { is_expected.to be true } + end + + context 'employee_type G' do + let(:employee_type_code) { 'G' } + it { is_expected.to be true } + end + + context 'employee_type L' do + let(:employee_type_code) { 'L' } + it { is_expected.to be true } + end + + context 'employee_type Q' do + let(:employee_type_code) { 'Q' } + it { is_expected.to be true } + end + + context 'employee_type R' do + let(:employee_type_code) { 'R' } + it { is_expected.to be true } + end + + context 'employee_type S' do + let(:employee_type_code) { 'S' } + it { is_expected.to be true } + end + + context 'employee_type X' do + let(:employee_type_code) { 'X' } + it { is_expected.to be false } + end + end + + describe '#authenticated_nims_other?' do + subject { user.authenticated_nims_other? } + + context 'employee_type T' do + let(:employee_type_code) { 'T' } + it { is_expected.to be true } + end + + context 'employee_type Z' do + let(:employee_type_code) { 'Z' } + it { is_expected.to be true } + end + + context 'employee_type X' do + let(:employee_type_code) { 'X' } + it { is_expected.to be false } + end + end + + describe '#authenticated_nims?' do + subject { user.authenticated_nims? } + + context 'employee_type A' do + let(:employee_type_code) { 'A' } + it { is_expected.to be true } + end + + context 'employee_type T' do + let(:employee_type_code) { 'T' } + it { is_expected.to be true } + end + + context 'employee_type X' do + let(:employee_type_code) { 'X' } + it { is_expected.to be false } + end + end + + describe '#authenticated_external?' do + let(:employee_type_code) { nil } + subject { user.authenticated_external? } + it { is_expected.to be false } + end + + describe '#authenticated?' do + let(:employee_type_code) { 'A' } + subject { user.authenticated? } + it { is_expected.to be true } + end + end +end diff --git a/hyrax/spec/models/work_spec.rb b/hyrax/spec/models/work_spec.rb index 9f9d3867..6d7b6acc 100644 --- a/hyrax/spec/models/work_spec.rb +++ b/hyrax/spec/models/work_spec.rb @@ -1,9 +1,17 @@ -# Generated via -# `rails generate hyrax:work Work` require 'rails_helper' RSpec.describe Work do - it "has tests" do - skip "Add your tests here" + + describe 'title' do + context 'valid title' do + subject { build(:work, title: ['Foo Bar']) } + it { is_expected.to be_valid } + it { expect(subject.title).to match_array ['Foo Bar'] } + end + + context 'missing title' do + subject { build(:work, title: nil) } + it { is_expected.to_not be_valid } + end end end diff --git a/hyrax/spec/presenters/hyrax/dataset_presenter_spec.rb b/hyrax/spec/presenters/hyrax/dataset_presenter_spec.rb new file mode 100644 index 00000000..1d69ff0f --- /dev/null +++ b/hyrax/spec/presenters/hyrax/dataset_presenter_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Dataset` +require 'rails_helper' + +RSpec.describe Hyrax::DatasetPresenter do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/presenters/hyrax/image_presenter_spec.rb b/hyrax/spec/presenters/hyrax/image_presenter_spec.rb new file mode 100644 index 00000000..fc371feb --- /dev/null +++ b/hyrax/spec/presenters/hyrax/image_presenter_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Image` +require 'rails_helper' + +RSpec.describe Hyrax::ImagePresenter do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/presenters/hyrax/nims_file_set_presenter_spec.rb b/hyrax/spec/presenters/hyrax/nims_file_set_presenter_spec.rb new file mode 100644 index 00000000..2c92880d --- /dev/null +++ b/hyrax/spec/presenters/hyrax/nims_file_set_presenter_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +RSpec.describe Hyrax::NimsFileSetPresenter do + let(:presenter) { described_class.new(solr_document, nil) } + let(:solr_document) { double(mime_type: mime_type) } + + describe 'mime_type' do + subject { presenter.mime_type } + context 'some/mime_type' do + let(:mime_type) { 'some/mime_type' } + it { is_expected.to eql('some/mime_type') } + end + context 'no mime type' do + let(:mime_type) { nil } + it { is_expected.to be_nil } + end + end + + describe 'csv?' do + subject { presenter.csv? } + context 'text/csv' do + let(:mime_type) { 'text/csv' } + it { is_expected.to be true } + end + context 'APPLICATION/CSV' do + let(:mime_type) { 'APPLICATION/CSV' } + it { is_expected.to be true } + end + context 'some/mime_type' do + let(:mime_type) { 'some/mime_type' } + it { is_expected.to be false } + end + context 'no mime type' do + let(:mime_type) { nil } + it { is_expected.to be false } + end + end +end diff --git a/hyrax/spec/presenters/hyrax/publication_presenter_spec.rb b/hyrax/spec/presenters/hyrax/publication_presenter_spec.rb new file mode 100644 index 00000000..6653f7e6 --- /dev/null +++ b/hyrax/spec/presenters/hyrax/publication_presenter_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work Publication` +require 'rails_helper' + +RSpec.describe Hyrax::PublicationPresenter do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/rails_helper.rb b/hyrax/spec/rails_helper.rb index bbe1ba57..fac43a21 100644 --- a/hyrax/spec/rails_helper.rb +++ b/hyrax/spec/rails_helper.rb @@ -5,6 +5,11 @@ # Prevent database truncation if the environment is production abort("The Rails environment is running in production mode!") if Rails.env.production? require 'rspec/rails' +require 'support/factory_bot' +require 'support/input_support' +# require 'capybara/rails' # might need to turn this on in future +# require 'capybara/rspec' # might need to turn this on in future + # Add additional requires below this line. Rails is not loaded until this point! # Requires supporting ruby files with custom matchers and macros, etc, in @@ -27,6 +32,8 @@ ActiveRecord::Migration.maintain_test_schema! RSpec.configure do |config| + config.include Devise::Test::ControllerHelpers, type: :view + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" diff --git a/hyrax/spec/renderers/nested_affiliation_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_affiliation_attribute_renderer_spec.rb new file mode 100644 index 00000000..16a1617c --- /dev/null +++ b/hyrax/spec/renderers/nested_affiliation_attribute_renderer_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe NestedAffiliationAttributeRenderer do + let(:html) { described_class.new('Affiliation', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_person).complex_person.first.complex_affiliation.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Affiliation') + is_expected.to have_css('div.row label', text: 'Job title') + is_expected.to have_css('div.row', text: 'Principal Investigator') + + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'University') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Department') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Research') + end +end diff --git a/hyrax/spec/renderers/nested_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_attribute_renderer_spec.rb new file mode 100644 index 00000000..d0179f00 --- /dev/null +++ b/hyrax/spec/renderers/nested_attribute_renderer_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +RSpec.describe NestedAttributeRenderer do + let(:renderer) { described_class.new('Attribute', nested_value.to_json) } + let(:nested_value) { 12345 } + subject { Capybara.string(html) } + + # NB: private methods in this class are tested indirectly but other nested readers + + describe '#render_dl_row' do + let(:html) { renderer.render_dl_row } + it 'generates the correct fields' do + is_expected.to have_css('dt', text: 'Attribute') + is_expected.to have_link('12345') + end + end +end diff --git a/hyrax/spec/renderers/nested_custom_property_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_custom_property_attribute_renderer_spec.rb new file mode 100644 index 00000000..b357a501 --- /dev/null +++ b/hyrax/spec/renderers/nested_custom_property_attribute_renderer_spec.rb @@ -0,0 +1,12 @@ +require 'rails_helper' + +RSpec.describe NestedCustomPropertyAttributeRenderer do + let(:html) { described_class.new('Custom property', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_custom_property).custom_property.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Custom property') + is_expected.to have_css('div.row label', text: 'Full name') + is_expected.to have_css('div.row', text: 'Foo Bar') + end +end diff --git a/hyrax/spec/renderers/nested_date_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_date_attribute_renderer_spec.rb new file mode 100644 index 00000000..5657c688 --- /dev/null +++ b/hyrax/spec/renderers/nested_date_attribute_renderer_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe NestedDateAttributeRenderer do + let(:html) { described_class.new('Date', nested_value.to_json).render } + subject { Capybara.string(html) } + + context 'valid date' do + let(:nested_value) { build(:dataset, :with_complex_date).complex_date.first } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Date') + is_expected.to have_css('div.row label', text: 'Published') + is_expected.to have_css('div.row', text: '28/10/1978') + end + end + + context 'invalid date' do + let(:nested_value) { { date: ["Foo"], description: ["Bar"] } } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Date') + is_expected.to have_css('div.row label', text: 'Bar') + is_expected.to have_css('div.row', text: 'Foo') + end + end +end diff --git a/hyrax/spec/renderers/nested_desc_id_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_desc_id_attribute_renderer_spec.rb new file mode 100644 index 00000000..9676fbfa --- /dev/null +++ b/hyrax/spec/renderers/nested_desc_id_attribute_renderer_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +RSpec.describe NestedDescIdAttributeRenderer do + let(:html) { described_class.new('Description / identifier', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_chemical_composition).complex_specimen_type.first.complex_chemical_composition.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Description / identifier') + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'chemical composition 1') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'chemical_composition/1234567') + end +end diff --git a/hyrax/spec/renderers/nested_event_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_event_attribute_renderer_spec.rb new file mode 100644 index 00000000..46c8428d --- /dev/null +++ b/hyrax/spec/renderers/nested_event_attribute_renderer_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe NestedEventAttributeRenderer do + let(:html) { described_class.new('Event', nested_value.to_json).render } + let(:nested_value) { build(:publication, :with_complex_event).complex_event.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Event') + is_expected.to have_css('div.row label', text: 'Title') + is_expected.to have_css('div.row', text: 'Event-Title-123') + + is_expected.to have_css('div.row label', text: 'Location') + is_expected.to have_css('div.row', text: 'New Scotland Yard') + + is_expected.to have_css('div.row label', text: 'Start date') + is_expected.to have_css('div.row', text: '2018-12-25') + + is_expected.to have_css('div.row label', text: 'End date') + is_expected.to have_css('div.row', text: '2019-01-01') + + is_expected.to have_css('div.row label', text: 'Invitation status') + is_expected.to have_css('div.row', text: 'true') + end +end diff --git a/hyrax/spec/renderers/nested_identifier_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_identifier_attribute_renderer_spec.rb new file mode 100644 index 00000000..64425b32 --- /dev/null +++ b/hyrax/spec/renderers/nested_identifier_attribute_renderer_spec.rb @@ -0,0 +1,25 @@ +require 'rails_helper' + +RSpec.describe NestedIdentifierAttributeRenderer do + let(:html) { described_class.new('Identifier', nested_value.to_json).render } + + context 'doi' do + let(:nested_value) { build(:dataset, :with_complex_identifier).complex_identifier.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Identifier') + is_expected.to have_css('div.row label', text: 'DOI') + is_expected.to have_css('div.row a[href="https://doi.org/10.0.1111"]', text: 'doi:10.0.1111') + end + end + + context 'handle' do + let(:nested_value) { build(:dataset, :with_complex_relation).complex_relation.first.complex_identifier.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Identifier') + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row a[href="https://hdl.handle.net/4263537/400"]', text: 'hdl:4263537/400') + end + end +end diff --git a/hyrax/spec/renderers/nested_instrument_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_instrument_attribute_renderer_spec.rb new file mode 100644 index 00000000..e4d23553 --- /dev/null +++ b/hyrax/spec/renderers/nested_instrument_attribute_renderer_spec.rb @@ -0,0 +1,89 @@ +require 'rails_helper' + +RSpec.describe NestedInstrumentAttributeRenderer do + let(:html) { described_class.new('Instrument', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_instrument).complex_instrument.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Instrument') + is_expected.to have_css('div.row label', text: 'Title') + is_expected.to have_css('div.row a', text: 'Instrument title') + + is_expected.to have_css('div.row label', text: 'Alternative title') + is_expected.to have_css('div.row', text: 'An instrument title') + + is_expected.to have_css('div.row label', text: 'Published') + is_expected.to have_css('div.row', text: '14/02/2018') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'Instrument description') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'instrument/27213727') + + is_expected.to have_css('div.row label', text: 'Instrument function') + is_expected.to have_css('div.row label', text: 'Column number') + is_expected.to have_css('div.row', text: '1') + + is_expected.to have_css('div.row label', text: 'Category') + is_expected.to have_css('div.row', text: 'some value') + + is_expected.to have_css('div.row label', text: 'Sub category') + is_expected.to have_css('div.row', text: 'some other value') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'Instrument function description') + + is_expected.to have_css('div.row label', text: 'Manufacturer') + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'Foo') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Bar') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Manufacturer') + + is_expected.to have_css('div.row label', text: 'Local') + is_expected.to have_css('div.row', text: '123456789m') + + is_expected.to have_css('div.row label', text: 'Model number') + is_expected.to have_css('div.row', text: '123xfty') + + is_expected.to have_css('div.row label', text: 'Operator') + is_expected.to have_css('div.row label', text: 'Name') + is_expected.to have_css('div.row a', text: 'Name of operator') + + is_expected.to have_css('div.row label', text: 'Identifier - Local') + is_expected.to have_css('div.row', text: '123456789mo') + + is_expected.to have_css('div.row label', text: 'Affiliation') + is_expected.to have_css('div.row label', text: 'Job title') + is_expected.to have_css('div.row', text: 'Principal Investigator') + + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'University') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Department') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Research') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'operator/データ測定者・計算者') + + is_expected.to have_css('div.row label', text: 'Managing organization') + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'Managing organization name') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'BarBar') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Managing organization') + + is_expected.to have_css('div.row label', text: 'Local') + is_expected.to have_css('div.row', text: '123456789mo') + end +end diff --git a/hyrax/spec/renderers/nested_instrument_function_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_instrument_function_attribute_renderer_spec.rb new file mode 100644 index 00000000..50042a32 --- /dev/null +++ b/hyrax/spec/renderers/nested_instrument_function_attribute_renderer_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe NestedInstrumentFunctionAttributeRenderer do + let(:html) { described_class.new('Instrument function', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_instrument).complex_instrument.first.instrument_function.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Instrument function') + + is_expected.to have_css('div.row label', text: 'Column number') + is_expected.to have_css('div.row', text: '1') + + is_expected.to have_css('div.row label', text: 'Category') + is_expected.to have_css('div.row', text: 'some value') + + is_expected.to have_css('div.row label', text: 'Sub category') + is_expected.to have_css('div.row', text: 'some other value') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'Instrument function description') + end +end diff --git a/hyrax/spec/renderers/nested_material_type_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_material_type_attribute_renderer_spec.rb new file mode 100644 index 00000000..7da5926a --- /dev/null +++ b/hyrax/spec/renderers/nested_material_type_attribute_renderer_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe NestedMaterialTypeAttributeRenderer do + let(:html) { described_class.new('Material type', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_specimen_type).complex_specimen_type.first.complex_material_type.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Material type') + + is_expected.to have_css('div.row label', text: 'Material type') + is_expected.to have_css('div.row', text: 'some material type') + + is_expected.to have_css('div.row label', text: 'Material sub type') + is_expected.to have_css('div.row', text: 'some other material sub type') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'material/ewfqwefqwef') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'material description') + end +end diff --git a/hyrax/spec/renderers/nested_organization_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_organization_attribute_renderer_spec.rb new file mode 100644 index 00000000..322209fe --- /dev/null +++ b/hyrax/spec/renderers/nested_organization_attribute_renderer_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +RSpec.describe NestedOrganizationAttributeRenderer do + let(:html) { described_class.new('Organization', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_person).complex_person.first.complex_affiliation.first.complex_organization.first } + subject { Capybara.string(html) } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Organization') + + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'University') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Department') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Research') + end +end diff --git a/hyrax/spec/renderers/nested_person_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_person_attribute_renderer_spec.rb new file mode 100644 index 00000000..107dcf21 --- /dev/null +++ b/hyrax/spec/renderers/nested_person_attribute_renderer_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' + +RSpec.describe NestedPersonAttributeRenderer do + let(:html) { described_class.new('Person', nested_value.to_json).render } + subject { Capybara.string(html) } + + context 'with name' do + let(:nested_value) { build(:dataset, :with_complex_person).complex_person.first } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Person') + + is_expected.to have_css('div.row label', text: 'Name') + is_expected.to have_css('div.row a', text: 'Anamika') + + is_expected.to have_css('div.row label', text: 'Identifier - Local') + is_expected.to have_css('div.row', text: '123456') + + is_expected.to have_css('div.row label', text: 'Affiliation') + is_expected.to have_css('div.row label', text: 'Job title') + is_expected.to have_css('div.row', text: 'Principal Investigator') + + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'University') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Department') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Research') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'operator/データ測定者・計算者') + end + end + + context 'with first_name and last_name' do + let(:nested_value) { { first_name: ['Foo'], last_name: ['Bar'] } } + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Person') + is_expected.to have_css('div.row label', text: 'Name') + is_expected.to have_css('div.row a', text: 'Foo Bar') + end + end +end diff --git a/hyrax/spec/renderers/nested_purchase_record_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_purchase_record_attribute_renderer_spec.rb new file mode 100644 index 00000000..06f8b250 --- /dev/null +++ b/hyrax/spec/renderers/nested_purchase_record_attribute_renderer_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe NestedPurchaseRecordAttributeRenderer do + let(:html) { described_class.new('Purchase record', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_specimen_type).complex_specimen_type.first.complex_purchase_record.first } + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Purchase record') + + is_expected.to have_css('div.row label', text: 'Title') + is_expected.to have_css('div.row a', text: 'Purchase record title') + + is_expected.to have_css('div.row label', text: 'Date') + is_expected.to have_css('div.row', text: '2018-02-14') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'purchase_record/123456') + + is_expected.to have_css('div.row label', text: 'Supplier') + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'Fooss') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Barss') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Supplier') + + is_expected.to have_css('div.row label', text: 'Local') + is_expected.to have_css('div.row', text: 'supplier/123456789') + + is_expected.to have_css('div.row label', text: 'Manufacturer') + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'Foo') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Bar') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Manufacturer') + + is_expected.to have_css('div.row label', text: 'Local') + is_expected.to have_css('div.row', text: 'manufacturer/123456789') + + is_expected.to have_css('div.row label', text: 'Purchase record item') + is_expected.to have_css('div.row', text: 'Has a purchase record item') + end +end diff --git a/hyrax/spec/renderers/nested_relation_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_relation_attribute_renderer_spec.rb new file mode 100644 index 00000000..64eb22f3 --- /dev/null +++ b/hyrax/spec/renderers/nested_relation_attribute_renderer_spec.rb @@ -0,0 +1,20 @@ +require 'rails_helper' + +RSpec.describe NestedRelationAttributeRenderer do + let(:html) { described_class.new('Relationship', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_relation).complex_relation.first } + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Relationship') + + is_expected.to have_css('div.row label', text: 'Title') + is_expected.to have_link("A relation label", href: 'http://example.com/relation') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row a[href="https://hdl.handle.net/4263537/400"]', text: 'hdl:4263537/400') + + is_expected.to have_css('div.row label', text: 'Relationship') + is_expected.to have_css('div.row', text: 'is new version of') + end +end diff --git a/hyrax/spec/renderers/nested_rights_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_rights_attribute_renderer_spec.rb new file mode 100644 index 00000000..8bade046 --- /dev/null +++ b/hyrax/spec/renderers/nested_rights_attribute_renderer_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +RSpec.describe NestedRightsAttributeRenderer do + let(:html) { described_class.new('Rights', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_rights).complex_rights.first } + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Rights') + + is_expected.to have_css('div.row label', text: 'Rights') + is_expected.to have_css('div.row', text: 'http://creativecommons.org/publicdomain/zero/1.0/') + + is_expected.to have_css('div.row label', text: 'Date') + is_expected.to have_css('div.row', text: '1978-10-28') + end +end diff --git a/hyrax/spec/renderers/nested_source_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_source_attribute_renderer_spec.rb new file mode 100644 index 00000000..2554f3d1 --- /dev/null +++ b/hyrax/spec/renderers/nested_source_attribute_renderer_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' + +RSpec.describe NestedSourceAttributeRenderer do + let(:html) { described_class.new('Source', nested_value.to_json).render } + let(:nested_value) { build(:publication, :with_complex_source).complex_source.first } + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Source') + + is_expected.to have_css('div.row label', text: 'Title') + is_expected.to have_link('Test journal') + + is_expected.to have_css('div.row label', text: 'Alternative title') + is_expected.to have_css('div.row', text: 'Sub title for journal') + + is_expected.to have_css('div.row label', text: 'Contributor') + is_expected.to have_css('div.row label', text: 'Name') + is_expected.to have_link('AR') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Editor') + + is_expected.to have_css('div.row label', text: 'Local') + is_expected.to have_css('div.row', text: '1234567') + + is_expected.to have_css('div.row label', text: 'Issue') + is_expected.to have_css('div.row', text: '34') + + is_expected.to have_css('div.row label', text: 'Volume') + is_expected.to have_css('div.row', text: '3') + + is_expected.to have_css('div.row label', text: 'Sequence number') + is_expected.to have_css('div.row', text: '1.2.2') + + is_expected.to have_css('div.row label', text: 'Start page') + is_expected.to have_css('div.row', text: '4') + + is_expected.to have_css('div.row label', text: 'End page') + is_expected.to have_css('div.row', text: '12') + + is_expected.to have_css('div.row label', text: 'Total number of pages') + is_expected.to have_css('div.row', text: '8') + end +end diff --git a/hyrax/spec/renderers/nested_specimen_type_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_specimen_type_attribute_renderer_spec.rb new file mode 100644 index 00000000..91b0e311 --- /dev/null +++ b/hyrax/spec/renderers/nested_specimen_type_attribute_renderer_spec.rb @@ -0,0 +1,101 @@ +require 'rails_helper' + +RSpec.describe NestedSpecimenTypeAttributeRenderer do + let(:html) { described_class.new('Speciman type', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_specimen_type).complex_specimen_type.first } + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Speciman type') + + is_expected.to have_css('div.row label', text: 'Title') + is_expected.to have_css('div.row', text: 'Specimen 1') + + is_expected.to have_css('div.row label', text: 'Chemical composition') + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'chemical composition 1') + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'chemical_composition/1234567') + + is_expected.to have_css('div.row label', text: 'Crystallographic structure') + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'crystallographic_structure 1') + is_expected.to have_css('div.row label', text: 'Identifier') + is_expected.to have_css('div.row', text: 'crystallographic_structure/123456') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'Specimen description') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'specimen/1234567') + + is_expected.to have_css('div.row label', text: 'Material type') + is_expected.to have_css('div.row', text: 'some material type') + + is_expected.to have_css('div.row label', text: 'Material sub type') + is_expected.to have_css('div.row', text: 'some other material sub type') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'material/ewfqwefqwef') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'material description') + + is_expected.to have_css('div.row label', text: 'Purchase record') + is_expected.to have_css('div.row label', text: 'Title') + is_expected.to have_link('Purchase record title') + + is_expected.to have_css('div.row label', text: 'Date') + is_expected.to have_css('div.row', text: '2018-02-14') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'purchase_record/123456') + + is_expected.to have_css('div.row label', text: 'Supplier') + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_link('Fooss') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Barss') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Supplier') + + is_expected.to have_css('div.row label', text: 'Local') + is_expected.to have_css('div.row', text: 'supplier/123456789') + + is_expected.to have_css('div.row label', text: 'Manufacturer') + is_expected.to have_css('div.row label', text: 'Organization') + is_expected.to have_css('div.row a', text: 'Foo') + + is_expected.to have_css('div.row label', text: 'Sub organization') + is_expected.to have_css('div.row', text: 'Bar') + + is_expected.to have_css('div.row label', text: 'Role') + is_expected.to have_css('div.row', text: 'Manufacturer') + + is_expected.to have_css('div.row label', text: 'Local') + is_expected.to have_css('div.row', text: 'manufacturer/123456789') + + is_expected.to have_css('div.row label', text: 'Purchase record item') + is_expected.to have_css('div.row', text: 'Has a purchase record item') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'shape description') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'shape/123456') + + is_expected.to have_css('div.row label', text: 'Category') + is_expected.to have_css('div.row', text: 'structural feature category') + + is_expected.to have_css('div.row label', text: 'Sub category') + is_expected.to have_css('div.row', text: 'structural feature sub category') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'structural feature description') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'structural_feature/123456') + end +end diff --git a/hyrax/spec/renderers/nested_structural_feature_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_structural_feature_attribute_renderer_spec.rb new file mode 100644 index 00000000..b639e73f --- /dev/null +++ b/hyrax/spec/renderers/nested_structural_feature_attribute_renderer_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + +RSpec.describe NestedStructuralFeatureAttributeRenderer do + let(:html) { described_class.new('Structural feature', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_specimen_type).complex_specimen_type.first.complex_structural_feature.first } + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Structural feature') + + is_expected.to have_css('div.row label', text: 'Category') + is_expected.to have_css('div.row', text: 'structural feature category') + + is_expected.to have_css('div.row label', text: 'Sub category') + is_expected.to have_css('div.row', text: 'structural feature sub category') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'structural feature description') + + is_expected.to have_css('div.row label', text: 'Identifier - Persistent') + is_expected.to have_css('div.row', text: 'structural_feature/123456') + end +end diff --git a/hyrax/spec/renderers/nested_version_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_version_attribute_renderer_spec.rb new file mode 100644 index 00000000..f5e78755 --- /dev/null +++ b/hyrax/spec/renderers/nested_version_attribute_renderer_spec.rb @@ -0,0 +1,20 @@ +require 'rails_helper' + +RSpec.describe NestedVersionAttributeRenderer do + let(:html) { described_class.new('Version', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_version).complex_version.first } + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Version') + + is_expected.to have_css('div.row label', text: 'Version') + is_expected.to have_css('div.row', text: '1.0') + + is_expected.to have_css('div.row label', text: 'Description') + is_expected.to have_css('div.row', text: 'Creating the first version') + + is_expected.to have_css('div.row label', text: 'Date') + is_expected.to have_css('div.row', text: '28/10/1978') + end +end diff --git a/hyrax/spec/services/analysis_field_service_spec.rb b/hyrax/spec/services/analysis_field_service_spec.rb new file mode 100644 index 00000000..a741f0f8 --- /dev/null +++ b/hyrax/spec/services/analysis_field_service_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe AnalysisFieldService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["bio property/バイオ特性", "bio property"], + ["crystallograpgy/結晶学", "crystallograpgy"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('bio property')).to eq({ + "label" => "bio property/バイオ特性", + "id" => "bio property", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('bio property/バイオ特性')).to eq({ + "label" => "bio property/バイオ特性", + "id" => "bio property", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('bio property/バイオ特性')).to eq({ + "label" => "bio property/バイオ特性", + "id" => "bio property", + "active" => true + }) + expect(service.find_by_id_or_label('bio property')).to eq({ + "label" => "bio property/バイオ特性", + "id" => "bio property", + "active" => true + }) + end + end + +end diff --git a/hyrax/spec/services/characterization_method_service_spec.rb b/hyrax/spec/services/characterization_method_service_spec.rb new file mode 100644 index 00000000..277f143c --- /dev/null +++ b/hyrax/spec/services/characterization_method_service_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe CharacterizationMethodService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["charge distribution/荷電分布", "charge distribution"], + ["dilatometry/膨張計", "dilatometry"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('charge distribution')).to eq({ + "label" => "charge distribution/荷電分布", + "id" => "charge distribution", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('charge distribution/荷電分布')).to eq({ + "label" => "charge distribution/荷電分布", + "id" => "charge distribution", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('charge distribution/荷電分布')).to eq({ + "label" => "charge distribution/荷電分布", + "id" => "charge distribution", + "active" => true + }) + expect(service.find_by_id_or_label('charge distribution')).to eq({ + "label" => "charge distribution/荷電分布", + "id" => "charge distribution", + "active" => true + }) + end + end + +end diff --git a/hyrax/spec/services/computational_method_service_spec.rb b/hyrax/spec/services/computational_method_service_spec.rb new file mode 100644 index 00000000..9a51e963 --- /dev/null +++ b/hyrax/spec/services/computational_method_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe ComputationalMethodService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["CALPHAD/カルパッド", "CALPHAD"], + ["molecular dynamics/分子動力学", "molecular dynamics"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('CALPHAD')).to eq({ + "label" => "CALPHAD/カルパッド", + "id" => "CALPHAD", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('CALPHAD/カルパッド')).to eq({ + "label" => "CALPHAD/カルパッド", + "id" => "CALPHAD", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('CALPHAD/カルパッド')).to eq({ + "label" => "CALPHAD/カルパッド", + "id" => "CALPHAD", + "active" => true + }) + expect(service.find_by_id_or_label('CALPHAD')).to eq({ + "label" => "CALPHAD/カルパッド", + "id" => "CALPHAD", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/data_origin_service_spec.rb b/hyrax/spec/services/data_origin_service_spec.rb new file mode 100644 index 00000000..58928e0c --- /dev/null +++ b/hyrax/spec/services/data_origin_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe DataOriginService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["experiments/実験", "experiments"], + ["informatics and data science/情報・データ科学", "informatics and data science"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('experiments')).to eq({ + "label" => "experiments/実験", + "id" => "experiments", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('experiments/実験')).to eq({ + "label" => "experiments/実験", + "id" => "experiments", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('experiments/実験')).to eq({ + "label" => "experiments/実験", + "id" => "experiments", + "active" => true + }) + expect(service.find_by_id_or_label('experiments')).to eq({ + "label" => "experiments/実験", + "id" => "experiments", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/date_service_spec.rb b/hyrax/spec/services/date_service_spec.rb new file mode 100644 index 00000000..e6d1cfa9 --- /dev/null +++ b/hyrax/spec/services/date_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe DateService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["Accepted", "http://purl.org/dc/terms/dateAccepted"], + ["Updated", "http://bibframe.org/vocab/changeDate"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('http://purl.org/dc/terms/dateAccepted')).to eq({ + "label" => "Accepted", + "id" => "http://purl.org/dc/terms/dateAccepted", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('Accepted')).to eq({ + "label" => "Accepted", + "id" => "http://purl.org/dc/terms/dateAccepted", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('http://purl.org/dc/terms/dateAccepted')).to eq({ + "label" => "Accepted", + "id" => "http://purl.org/dc/terms/dateAccepted", + "active" => true + }) + expect(service.find_by_id_or_label('Accepted')).to eq({ + "label" => "Accepted", + "id" => "http://purl.org/dc/terms/dateAccepted", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/identifier_service_spec.rb b/hyrax/spec/services/identifier_service_spec.rb new file mode 100644 index 00000000..ced80a16 --- /dev/null +++ b/hyrax/spec/services/identifier_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe IdentifierService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["eduPersonTargetedID", "edu person targeted id"], + ["Referred Identifier - Local", "referred identifier local"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('referred identifier local')).to eq({ + "label" => "Referred Identifier - Local", + "id" => "referred identifier local", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('Identifier - Local')).to eq({ + "label" => "Identifier - Local", + "id" => "identifier local", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('Identifier - Persistent')).to eq({ + "label" => "Identifier - Persistent", + "id" => "identifier persistent", + "active" => true + }) + expect(service.find_by_id_or_label('identifier persistent')).to eq({ + "label" => "Identifier - Persistent", + "id" => "identifier persistent", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/material_type_service_spec.rb b/hyrax/spec/services/material_type_service_spec.rb new file mode 100644 index 00000000..1fdf61fa --- /dev/null +++ b/hyrax/spec/services/material_type_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe MaterialTypeService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["ceramics/セラミックス", "ceramics"], + ["metals and alloys/金属・合金 -- Cu-containing/Cu含有物質", "metals and alloys -- Cu-containing"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('ceramics')).to eq({ + "label" => "ceramics/セラミックス", + "id" => "ceramics", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('ceramics/セラミックス')).to eq({ + "label" => "ceramics/セラミックス", + "id" => "ceramics", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('ceramics')).to eq({ + "label" => "ceramics/セラミックス", + "id" => "ceramics", + "active" => true + }) + expect(service.find_by_id_or_label('ceramics/セラミックス')).to eq({ + "label" => "ceramics/セラミックス", + "id" => "ceramics", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/measurement_environment_service_spec.rb b/hyrax/spec/services/measurement_environment_service_spec.rb new file mode 100644 index 00000000..7b5c187c --- /dev/null +++ b/hyrax/spec/services/measurement_environment_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe MeasurementEnvironmentService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["in air/空気中", "in air"], + ["in liquid/液体中", "in liquid"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('in air')).to eq({ + "label" => "in air/空気中", + "id" => "in air", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('in air/空気中')).to eq({ + "label" => "in air/空気中", + "id" => "in air", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('in air')).to eq({ + "label" => "in air/空気中", + "id" => "in air", + "active" => true + }) + expect(service.find_by_id_or_label('in air/空気中')).to eq({ + "label" => "in air/空気中", + "id" => "in air", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/processing_environment_service_spec.rb b/hyrax/spec/services/processing_environment_service_spec.rb new file mode 100644 index 00000000..73b5377f --- /dev/null +++ b/hyrax/spec/services/processing_environment_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe ProcessingEnvironmentService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["in liquid/液体中", "in liquid"], + ["in vacuum/真空中", "in vacuum"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('in liquid')).to eq({ + "label" => "in liquid/液体中", + "id" => "in liquid", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('in liquid/液体中')).to eq({ + "label" => "in liquid/液体中", + "id" => "in liquid", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('in liquid')).to eq({ + "label" => "in liquid/液体中", + "id" => "in liquid", + "active" => true + }) + expect(service.find_by_id_or_label('in liquid/液体中')).to eq({ + "label" => "in liquid/液体中", + "id" => "in liquid", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/properties_addressed_service_spec.rb b/hyrax/spec/services/properties_addressed_service_spec.rb new file mode 100644 index 00000000..9c6498c9 --- /dev/null +++ b/hyrax/spec/services/properties_addressed_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe PropertiesAddressedService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["chemical/化学的", "chemical"], + ["corrosion/腐食", "corrosion"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('chemical')).to eq({ + "label" => "chemical/化学的", + "id" => "chemical", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('chemical/化学的')).to eq({ + "label" => "chemical/化学的", + "id" => "chemical", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('chemical')).to eq({ + "label" => "chemical/化学的", + "id" => "chemical", + "active" => true + }) + expect(service.find_by_id_or_label('chemical/化学的')).to eq({ + "label" => "chemical/化学的", + "id" => "chemical", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/qa_select_service_extended_spec.rb b/hyrax/spec/services/qa_select_service_extended_spec.rb new file mode 100644 index 00000000..6ab8f392 --- /dev/null +++ b/hyrax/spec/services/qa_select_service_extended_spec.rb @@ -0,0 +1,67 @@ +require 'rails_helper' + +RSpec.describe QaSelectServiceExtended do + let(:service) { described_class.new('identifiers') } + + describe "#find_by_id" do + subject { service.find_by_id(id) } + context 'found' do + let(:id) { 'referred identifier local' } + it { is_expected.to eql({ + "label" => "Referred Identifier - Local", + "id" => "referred identifier local", + "active" => true + }) + } + end + context 'not found' do + let(:id) { 'foo bar' } + it { is_expected.to eql({}) } + end + end + + describe '#find_by_label' do + subject { service.find_by_label(label) } + context 'found' do + let(:label) { 'Identifier - Local' } + it { is_expected.to eql({ + "label" => "Identifier - Local", + "id" => "identifier local", + "active" => true + }) + } + end + context 'not found' do + let(:label) { 'foo bar' } + it { is_expected.to eql({}) } + end + end + + describe '#find_by_id_or_label' do + subject { service.find_by_id_or_label(id_or_label) } + context 'found' do + context 'label' do + let(:id_or_label) { 'Identifier - Persistent' } + it { is_expected.to eql({ + "label" => "Identifier - Persistent", + "id" => "identifier persistent", + "active" => true + }) + } + end + context 'id' do + let(:id_or_label) { 'identifier persistent' } + it { is_expected.to eql({ + "label" => "Identifier - Persistent", + "id" => "identifier persistent", + "active" => true + }) + } + end + end + context 'not found' do + let(:id_or_label) { 'foo bar' } + it { is_expected.to eql({}) } + end + end +end diff --git a/hyrax/spec/services/relationship_service_spec.rb b/hyrax/spec/services/relationship_service_spec.rb new file mode 100644 index 00000000..6703f075 --- /dev/null +++ b/hyrax/spec/services/relationship_service_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe RelationshipService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["is supplemented by", "isSupplementedBy"], + ["is previous version of", "isPreviousVersionOf"], + ) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('isSupplementedBy')).to eq({ + "label" => "is supplemented by", + "id" => "isSupplementedBy", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('is supplemented by')).to eq({ + "label" => "is supplemented by", + "id" => "isSupplementedBy", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('isSupplementedBy')).to eq({ + "label" => "is supplemented by", + "id" => "isSupplementedBy", + "active" => true + }) + expect(service.find_by_id_or_label('is supplemented by')).to eq({ + "label" => "is supplemented by", + "id" => "isSupplementedBy", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/rights_service_spec.rb b/hyrax/spec/services/rights_service_spec.rb new file mode 100644 index 00000000..95d005b2 --- /dev/null +++ b/hyrax/spec/services/rights_service_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe RightsService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["Creative Commons BY Attribution 4.0 International", "https://creativecommons.org/licenses/by/4.0/"], + ["Creative Commons Public Domain Mark 1.0", "http://creativecommons.org/publicdomain/mark/1.0/"], + ) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('http://creativecommons.org/publicdomain/mark/1.0/')).to eq({ + "label" => "Creative Commons Public Domain Mark 1.0", + "id" => "http://creativecommons.org/publicdomain/mark/1.0/", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('Creative Commons Public Domain Mark 1.0')).to eq({ + "label" => "Creative Commons Public Domain Mark 1.0", + "id" => "http://creativecommons.org/publicdomain/mark/1.0/", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('http://creativecommons.org/publicdomain/mark/1.0/')).to eq({ + "label" => "Creative Commons Public Domain Mark 1.0", + "id" => "http://creativecommons.org/publicdomain/mark/1.0/", + "active" => true + }) + expect(service.find_by_id_or_label('Creative Commons Public Domain Mark 1.0')).to eq({ + "label" => "Creative Commons Public Domain Mark 1.0", + "id" => "http://creativecommons.org/publicdomain/mark/1.0/", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/rights_statement_service_spec.rb b/hyrax/spec/services/rights_statement_service_spec.rb new file mode 100644 index 00000000..557e70e6 --- /dev/null +++ b/hyrax/spec/services/rights_statement_service_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe RightsStatementService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["In Copyright", "http://rightsstatements.org/vocab/InC/1.0/"], + ["Copyright Not Evaluated", "http://rightsstatements.org/vocab/CNE/1.0/"], + ) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('http://rightsstatements.org/vocab/CNE/1.0/')).to eq({ + "label" => "Copyright Not Evaluated", + "id" => "http://rightsstatements.org/vocab/CNE/1.0/", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('Copyright Not Evaluated')).to eq({ + "label" => "Copyright Not Evaluated", + "id" => "http://rightsstatements.org/vocab/CNE/1.0/", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('http://rightsstatements.org/vocab/CNE/1.0/')).to eq({ + "label" => "Copyright Not Evaluated", + "id" => "http://rightsstatements.org/vocab/CNE/1.0/", + "active" => true + }) + expect(service.find_by_id_or_label('Copyright Not Evaluated')).to eq({ + "label" => "Copyright Not Evaluated", + "id" => "http://rightsstatements.org/vocab/CNE/1.0/", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/role_service_spec.rb b/hyrax/spec/services/role_service_spec.rb new file mode 100644 index 00000000..f9e352de --- /dev/null +++ b/hyrax/spec/services/role_service_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +RSpec.describe RoleService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["translator/翻訳者", "translator"], + ["data curator/データキュレーター", "data curator"], + ) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('translator')).to eq({ + "label" => "translator/翻訳者", + "id" => "translator", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('translator/翻訳者')).to eq({ + "label" => "translator/翻訳者", + "id" => "translator", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('translator')).to eq({ + "label" => "translator/翻訳者", + "id" => "translator", + "active" => true + }) + expect(service.find_by_id_or_label('translator/翻訳者')).to eq({ + "label" => "translator/翻訳者", + "id" => "translator", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/structural_feature_service_spec.rb b/hyrax/spec/services/structural_feature_service_spec.rb new file mode 100644 index 00000000..83902698 --- /dev/null +++ b/hyrax/spec/services/structural_feature_service_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe StructuralFeatureService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["composites/複合材料 -- structural/構造", "composites -- structural"], + ["defects/欠陥", "defects"]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('defects')).to eq({ + "label" => "defects/欠陥", + "id" => "defects", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('defects/欠陥')).to eq({ + "label" => "defects/欠陥", + "id" => "defects", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('defects')).to eq({ + "label" => "defects/欠陥", + "id" => "defects", + "active" => true + }) + expect(service.find_by_id_or_label('defects/欠陥')).to eq({ + "label" => "defects/欠陥", + "id" => "defects", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/synthesis_and_processing_service_spec.rb b/hyrax/spec/services/synthesis_and_processing_service_spec.rb new file mode 100644 index 00000000..ee23a2c2 --- /dev/null +++ b/hyrax/spec/services/synthesis_and_processing_service_spec.rb @@ -0,0 +1,51 @@ +require 'rails_helper' + +RSpec.describe SynthesisAndProcessingService do + let(:service) { described_class.new } + + describe "#select_active_options" do + it "returns active terms" do + expect(service.select_active_options).to include( + ["casting/鋳造", "casting"], + [ + "annealing and homogenization/アニーリング_均一化処理 -- mechanical mixing/機械的混合", + "annealing and homogenization -- mechanical mixing" + ]) + end + end + + describe "find_by_id" do + it "returns active term matching id" do + expect(service.find_by_id('casting')).to eq({ + "label" => "casting/鋳造", + "id" => "casting", + "active" => true + }) + end + end + + describe "find_by_label" do + it "returns active term matching label" do + expect(service.find_by_label('casting/鋳造')).to eq({ + "label" => "casting/鋳造", + "id" => "casting", + "active" => true + }) + end + end + + describe "find_by_id_or_label" do + it "returns active term matching id or label" do + expect(service.find_by_id_or_label('casting')).to eq({ + "label" => "casting/鋳造", + "id" => "casting", + "active" => true + }) + expect(service.find_by_id_or_label('casting/鋳造')).to eq({ + "label" => "casting/鋳造", + "id" => "casting", + "active" => true + }) + end + end +end diff --git a/hyrax/spec/services/user_authorisation_service_spec.rb b/hyrax/spec/services/user_authorisation_service_spec.rb new file mode 100644 index 00000000..993b655e --- /dev/null +++ b/hyrax/spec/services/user_authorisation_service_spec.rb @@ -0,0 +1,37 @@ +require 'rails_helper' + +RSpec.describe UserAuthorisationService do + let(:user) { create(:user) } + let(:service) { described_class.new(user) } + + context 'without env vars' do + before do + allow(ENV).to receive(:[]).with('USER_AUTHORISATION_LDAP_HOST').and_return(nil) + allow(ENV).to receive(:[]).with('USER_AUTHORISATION_LDAP_BASE').and_return(nil) + allow(ENV).to receive(:[]).with('USER_AUTHORISATION_LDAP_ATTRIBUTE').and_return(nil) + end + it { expect(service.enabled?).to be false } + it { expect(service.update_attributes).to be false } + end + + context 'with env vars' do + before do + allow(ENV).to receive(:[]).with('USER_AUTHORISATION_LDAP_HOST').and_return('localhost') + allow(ENV).to receive(:[]).with('USER_AUTHORISATION_LDAP_BASE').and_return('ou=people,dc=test,dc=com') + allow(ENV).to receive(:[]).with('USER_AUTHORISATION_LDAP_ATTRIBUTE').and_return('uid') + end + it { expect(service.enabled?).to be true } + + describe '#update_attributes' do + let(:entry) { Net::LDAP::Entry.from_single_ldif_string( "dn: user1234\ncn: Alice Bloggs\nmail: newmail@example.com\nemployeeType: Z1234") } + before do + allow_any_instance_of(Net::LDAP).to receive(:search).with(base: 'ou=people,dc=test,dc=com', filter: Net::LDAP::Filter.eq('uid', user.username)).and_return([entry]) + service.update_attributes + end + it { expect(user.email).to eql('newmail@example.com') } + it { expect(user.display_name).to eql('Alice Bloggs') } + it { expect(user.employee_type_code).to eql('Z') } + it { expect(service.update_attributes).to be true } + end + end +end diff --git a/hyrax/spec/services/willow_sword/crosswalk_from_mdr_spec.rb b/hyrax/spec/services/willow_sword/crosswalk_from_mdr_spec.rb new file mode 100644 index 00000000..a2b253d2 --- /dev/null +++ b/hyrax/spec/services/willow_sword/crosswalk_from_mdr_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' + +RSpec.describe WillowSword::CrosswalkFromMdr do + let(:crosswalk) { described_class.new(File.join(fixture_path, 'xml', 'test.xml'), {} ) } + + describe '#map_xml' do + before { crosswalk.map_xml } + subject { crosswalk.mapped_metadata } + + it 'parses the xml' do + is_expected.to eql({ + :complex_identifier_attributes => [ + {:identifier => "123456789unknown", :scheme => "identifier local"}, + {:identifier => "project0012345*", :scheme => "project id"} + ], + :complex_person_attributes => [ + {:name => "Test1, TEST1", :complex_identifier_attributes => [{:identifier => "00112233", :scheme => "nims person id"}], :role => "author"}, + {:name => "Test2, TEST2", :complex_identifier_attributes => [{:identifier => "00445566", :scheme => "nims person id"}], :role => "data depositor"}, + {:name => "Test3, TEST3", :complex_identifier_attributes => [{:identifier => "00778899", :scheme => "nims person id"}], :role => "data curator"}, + {:name => "Test4, TEST4", :complex_identifier_attributes => [{:identifier => "09876543", :scheme => "nims person id"}], :role => "contact person"} + ], + :complex_organization_attributes => [ + {:organization => "NIMS"} + ], + :complex_date_attributes => [ + {:date => "2018-12-30", :description => "http://purl.org/dc/terms/created"}, + {:date => "2018-12-31", :description => "http://bibframe.org/vocab/changeDate"} + ], + :data_origin => ["experiments"], + :visibility => "open", + :title => ["unknown"], + :complex_specimen_type_attributes => [ + {:complex_identifier_attributes => [{:identifier => "999999999", :scheme => "identifier local"}], :description => ["unknown"]} + ] + }) + end + end + + describe '#get_files' do + let(:other_filepath) { File.join(fixture_path, 'xml', 'other.txt') } + before { crosswalk.get_files } + subject { crosswalk.files_metadata } + it { is_expected.to eql([{ "filename" => 'other.txt', "filepath" => other_filepath }] )} + end +end diff --git a/hyrax/spec/spec_helper.rb b/hyrax/spec/spec_helper.rb index ce33d66d..0d4c4055 100644 --- a/hyrax/spec/spec_helper.rb +++ b/hyrax/spec/spec_helper.rb @@ -1,96 +1,30 @@ -# This file was generated by the `rails generate rspec:install` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. -# -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. -# -# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +require 'coveralls' +require 'simplecov' +require 'webdrivers' +require 'sidekiq/testing' # use fake Redis for testing + +Coveralls.wear! +SimpleCov.start 'rails' do + # we do not unit test importers, as this is run-once code + add_filter "lib/importers" + + # additional code coverage groups for Hyrax + add_group 'Actors', 'app/actors' + add_group 'Forms', 'app/forms' + add_group 'Indexers', 'app/indexers' + add_group 'Inputs', 'app/inputs' + add_group 'Presenters', 'app/presenters' + add_group 'Renderers', 'app/renderers' + add_group 'Services', 'app/services' +end RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" expectations.include_chain_clauses_in_custom_matcher_descriptions = true end - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. mocks.verify_partial_doubles = true end - # This option will default to `:apply_to_host_groups` in RSpec 4 (and will - # have no way to turn it off -- the option exists only for backwards - # compatibility in RSpec 3). It causes shared context metadata to be - # inherited by the metadata hash of host groups and examples, rather than - # triggering implicit auto-inclusion in groups with matching metadata. config.shared_context_metadata_behavior = :apply_to_host_groups - -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # This allows you to limit a spec run to individual examples or groups - # you care about by tagging them with `:focus` metadata. When nothing - # is tagged with `:focus`, all examples get run. RSpec also provides - # aliases for `it`, `describe`, and `context` that include `:focus` - # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - config.filter_run_when_matching :focus - - # Allows RSpec to persist some state between runs in order to support - # the `--only-failures` and `--next-failure` CLI options. We recommend - # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" - - # Limits the available syntax to the non-monkey patched syntax that is - # recommended. For more details, see: - # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - config.disable_monkey_patching! - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = "doc" - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end end diff --git a/hyrax/spec/support/factory_bot.rb b/hyrax/spec/support/factory_bot.rb new file mode 100644 index 00000000..4f266ff9 --- /dev/null +++ b/hyrax/spec/support/factory_bot.rb @@ -0,0 +1,13 @@ +# spec/support/factory_bot.rb +RSpec.configure do |config| + config.include FactoryBot::Syntax::Methods +end + +# RSpec without Rails +RSpec.configure do |config| + config.include FactoryBot::Syntax::Methods + + # config.before(:suite) do + # FactoryBot.find_definitions + # end +end diff --git a/hyrax/spec/support/input_support.rb b/hyrax/spec/support/input_support.rb new file mode 100644 index 00000000..83f54bf3 --- /dev/null +++ b/hyrax/spec/support/input_support.rb @@ -0,0 +1,8 @@ +module InputSupport + extend ActiveSupport::Concern + include RSpec::Rails::HelperExampleGroup +end + +RSpec.configure do |config| + config.include InputSupport, type: :input +end diff --git a/hyrax/spec/views/hyrax/base/_form.html.erb_spec.rb b/hyrax/spec/views/hyrax/base/_form.html.erb_spec.rb new file mode 100644 index 00000000..7eb4d477 --- /dev/null +++ b/hyrax/spec/views/hyrax/base/_form.html.erb_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'hyrax/base/_form.html.erb', type: :view do + let(:work) { Publication.new } + let(:ability) { double } + let(:user) { FactoryBot.build(:user) } + + let(:form) do + Hyrax::PublicationForm.new(work, ability, controller) + end + + before do + allow(controller).to receive(:current_user).and_return(user) + assign(:form, form) + end + + describe 'tabs' do + it 'does not show the relationships tab' do + render + expect(rendered).not_to have_selector('#relationships[role="tabpanel"]') + expect(rendered).to have_selector('#metadata[role="tabpanel"]') + expect(rendered).to have_selector('#files[role="tabpanel"]') + expect(rendered).to have_selector('#share[data-param-key="publication"]') + end + end +end diff --git a/hyrax/spec/views/hyrax/base/_show_actions.html.erb_spec.rb b/hyrax/spec/views/hyrax/base/_show_actions.html.erb_spec.rb new file mode 100644 index 00000000..73a9411f --- /dev/null +++ b/hyrax/spec/views/hyrax/base/_show_actions.html.erb_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'hyrax/base/_show_actions.html.erb', type: :view do + let(:presenter) { Hyrax::WorkShowPresenter.new(solr_document, ability) } + let(:solr_document) { SolrDocument.new(attributes) } + let(:attributes) { { 'has_model_ssim' => ['Publication'], :id => '0r967372b' } } + let(:ability) { double } + + before do + allow(ability).to receive(:can?).with(:create, FeaturedWork).and_return(false) + allow(presenter).to receive(:show_deposit_for?).with(anything).and_return(true) + allow(presenter).to receive(:editor?).and_return(true) + end + + context 'as a registered user' do + it 'shows edit / delete / Add to collection links' do + render 'hyrax/base/show_actions', presenter: presenter + + expect(rendered).to have_link 'Edit' + expect(rendered).to have_link 'Delete' + expect(rendered).not_to have_link 'Add to collection' + expect(rendered).not_to have_button 'Add to collection' + end + end +end diff --git a/hyrax/spec/views/hyrax/base/show.html_spec.rb b/hyrax/spec/views/hyrax/base/show.html_spec.rb new file mode 100644 index 00000000..d84dfdb8 --- /dev/null +++ b/hyrax/spec/views/hyrax/base/show.html_spec.rb @@ -0,0 +1,42 @@ +require 'rails_helper' +include Warden::Test::Helpers + +RSpec.describe 'hyrax/base/show' do + let(:dataset) { create(:dataset, :open, :with_description_seq) } + let(:presenter) { Hyrax::DatasetPresenter.new(SolrDocument.new(dataset.to_solr), Ability.new(user), controller.request) } + + before do + allow(controller).to receive(:current_user).and_return(user) + login_as user if user.present? + assign(:presenter, presenter) + render + end + + # This test confirms the abstract is only visible if you are logged in + context 'unauthenticated user' do + let(:user) { nil } + it 'does not show the abstract' do + expect(rendered).to have_css('h2', text: dataset.title.first) + expect(rendered).not_to have_css('p.work_description', text: dataset.description.first) + expect(rendered).not_to have_css("span.Z3988[title*='rft.description=#{CGI.escape(dataset.description.first)}']") + end + end + + context 'authenticated non-researcher' do + let(:user) { build(:user, :nims_other) } + it 'shows the abstract' do + expect(rendered).to have_css('h2', text: dataset.title.first) + expect(rendered).to have_css('p.work_description', text: dataset.description.first) + expect(rendered).to have_css("span.Z3988[title*='rft.description=#{CGI.escape(dataset.description.first)}']") + end + end + + context 'authenticated NIMS Researcher' do + let(:user) { build(:user, :nims_researcher) } + it 'shows the abstract' do + expect(rendered).to have_css('h2', text: dataset.title.first) + expect(rendered).to have_css('p.work_description', text: dataset.description.first) + expect(rendered).to have_css("span.Z3988[title*='rft.description=#{CGI.escape(dataset.description.first)}']") + end + end +end diff --git a/hyrax/spec/views/hyrax/batch_uploads/_form.html.erb_spec.rb b/hyrax/spec/views/hyrax/batch_uploads/_form.html.erb_spec.rb new file mode 100644 index 00000000..b73bfca1 --- /dev/null +++ b/hyrax/spec/views/hyrax/batch_uploads/_form.html.erb_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'hyrax/batch_uploads/_form.html.erb', type: :view do + let(:work) { Publication.new } + let(:ability) { double('ability', current_user: user) } + let(:user) { FactoryBot.build(:user) } + + let(:form) do + Hyrax::Forms::BatchUploadForm.new(work, ability, controller) + end + + before do + view.lookup_context.prefixes += ['hyrax/base'] + allow(controller).to receive(:current_user).and_return(user) + assign(:form, form) + end + + describe 'tabs' do + it 'does not show the relationships tab' do + render + expect(rendered).not_to have_selector('#relationships[role="tabpanel"]') + expect(rendered).to have_selector('#metadata[role="tabpanel"]') + expect(rendered).to have_selector('#files[role="tabpanel"]') + end + end +end diff --git a/hyrax/spec/views/hyrax/dashboard/_sidebar.html.erb_spec.rb b/hyrax/spec/views/hyrax/dashboard/_sidebar.html.erb_spec.rb new file mode 100644 index 00000000..7fb380de --- /dev/null +++ b/hyrax/spec/views/hyrax/dashboard/_sidebar.html.erb_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'hyrax/dashboard/_sidebar.html.erb', type: :view do + let(:user) { FactoryBot.build(:user) } + let(:can_result) { false } + + before do + allow(view).to receive(:signed_in?).and_return(true) + allow(view).to receive(:current_user).and_return(user) + assign(:user, user) + allow(view).to receive(:can?).with(:read, :admin_dashboard).and_return(can_result) + allow(view).to receive(:can?).with(:manage_any, AdminSet).and_return(can_result) + allow(view).to receive(:can?).with(:review, :submissions).and_return(can_result) + allow(view).to receive(:can?).with(:manage, User).and_return(can_result) + allow(view).to receive(:can?).with(:update, :appearance).and_return(can_result) + allow(view).to receive(:can?).with(:manage, Hyrax::Feature).and_return(can_result) + allow(view).to receive(:can?).with(:manage, Sipity::WorkflowResponsibility).and_return(can_result) + allow(view).to receive(:can?).with(:manage, :collection_types).and_return(can_result) + end + + context 'with any user' do + before do + render + end + subject { rendered } + + it { is_expected.not_to have_link t('hyrax.admin.sidebar.collections') } + it { is_expected.to have_link t('hyrax.admin.sidebar.works') } + end + + context 'with a user who can read the admin dashboard' do + let(:can_result) { true } + + before do + render + end + subject { rendered } + + it { is_expected.to have_link t('hyrax.admin.sidebar.collections') } + it { is_expected.to have_link t('hyrax.admin.sidebar.works') } + end +end diff --git a/hyrax/spec/views/hyrax/datasets/_attribute_rows.html_spec.rb b/hyrax/spec/views/hyrax/datasets/_attribute_rows.html_spec.rb new file mode 100644 index 00000000..3e558c3b --- /dev/null +++ b/hyrax/spec/views/hyrax/datasets/_attribute_rows.html_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' +include Warden::Test::Helpers + +RSpec.describe 'hyrax/datasets/_attribute_rows' do + let(:partial) { 'hyrax/datasets/attribute_rows' } + let(:dataset) { create(:dataset, :open, :with_alternative_title, :with_complex_person, :with_keyword, :with_subject, + :with_language, :with_publisher, :with_complex_date, :with_complex_identifier, :with_complex_rights, + :with_complex_version, :with_resource_type, :with_complex_relation, :with_source) } + let(:presenter) { Hyrax::DatasetPresenter.new(SolrDocument.new(dataset.to_solr), Ability.new(user), controller.request) } + + before do + allow(controller).to receive(:current_user).and_return(user) + login_as user if user.present? + render partial: partial, locals: { presenter: presenter } + end + + # NB: the visibility of individual metadata components is set in app/models/ability.rb + # This test confirms the current expected behaviour (which is that most metadata is visible) + + context 'unauthenticated user' do + let(:user) { nil } + it 'shows the correct metadata' do + expect(rendered).to have_content('Alternative-Title-123') + expect(rendered).to have_content('Anamika') + expect(rendered).to have_content('University') + expect(rendered).to have_content('Keyword-123') + expect(rendered).to have_content('Subject-123') + expect(rendered).to have_content('Faroese') + expect(rendered).to have_content('Publisher-123') + expect(rendered).to have_content('1978-10-28') + expect(rendered).to have_content('10.0.1111') + expect(rendered).to have_content('http://creativecommons.org/publicdomain/zero/1.0/') + expect(rendered).to have_content('Creating the first version') + expect(rendered).to have_content('Resource-Type-123') + expect(rendered).to have_content('A relation label') + expect(rendered).to have_content('Source-123') + end + end + + context 'authenticated NIMS Researcher' do + let(:user) { create(:user, :nims_researcher) } + it 'shows the correct metadata' do + expect(rendered).to have_content('Alternative-Title-123') + expect(rendered).to have_content('Anamika') + expect(rendered).to have_content('University') + expect(rendered).to have_content('Keyword-123') + expect(rendered).to have_content('Subject-123') + expect(rendered).to have_content('Faroese') + expect(rendered).to have_content('Publisher-123') + expect(rendered).to have_content('1978-10-28') + expect(rendered).to have_content('10.0.1111') + expect(rendered).to have_content('http://creativecommons.org/publicdomain/zero/1.0/') + expect(rendered).to have_content('Creating the first version') + expect(rendered).to have_content('Resource-Type-123') + expect(rendered).to have_content('A relation label') + expect(rendered).to have_content('Source-123') + end + end +end diff --git a/hyrax/spec/views/hyrax/datasets/_form.html.erb_spec.rb b/hyrax/spec/views/hyrax/datasets/_form.html.erb_spec.rb new file mode 100644 index 00000000..ccb17bcb --- /dev/null +++ b/hyrax/spec/views/hyrax/datasets/_form.html.erb_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'hyrax/datasets/_form.html.erb', type: :view do + let(:work) { Dataset.new } + let(:ability) { double } + let(:user) { FactoryBot.build(:user) } + + let(:form) do + Hyrax::DatasetForm.new(work, ability, controller) + end + + before do + view.lookup_context.prefixes += ['hyrax/base'] + allow(controller).to receive(:current_user).and_return(user) + assign(:form, form) + end + + describe 'tabs' do + it 'does not show the relationships tab' do + render + expect(rendered).not_to have_selector('#relationships[role="tabpanel"]') + expect(rendered).to have_selector('#metadata[role="tabpanel"]') + expect(rendered).to have_selector('#files[role="tabpanel"]') + expect(rendered).to have_selector('#share[data-param-key="dataset"]') + end + end +end diff --git a/hyrax/spec/views/hyrax/images/_attribute_rows.html_spec.rb b/hyrax/spec/views/hyrax/images/_attribute_rows.html_spec.rb new file mode 100644 index 00000000..ffeca685 --- /dev/null +++ b/hyrax/spec/views/hyrax/images/_attribute_rows.html_spec.rb @@ -0,0 +1,56 @@ +require 'rails_helper' +include Warden::Test::Helpers + +RSpec.describe 'hyrax/images/_attribute_rows' do + let(:partial) { 'hyrax/images/attribute_rows' } + let(:image) { build(:image, :open, :with_alternative_title, :with_subject, :with_publisher, :with_language, + :with_keyword, :with_resource_type, :with_rights_statement, :with_complex_date, + :with_complex_identifier, :with_complex_person, :with_complex_rights, + :with_complex_version) } + let(:presenter) { Hyrax::ImagePresenter.new(SolrDocument.new(image.to_solr), Ability.new(user), controller.request) } + + before do + allow(controller).to receive(:current_user).and_return(user) + login_as user if user.present? + render partial: partial, locals: { presenter: presenter } + end + + # NB: the visibility of individual metadata components is set in app/models/ability.rb + # This test confirms the current expected behaviour (which is that most metadata is visible) + + context 'unauthenticated user' do + let(:user) { nil } + it 'shows the correct metadata' do + expect(rendered).to have_content('Alternative-Title-123') + expect(rendered).to have_content('Subject-123') + expect(rendered).to have_content('Publisher-123') + expect(rendered).to have_content('Faroese') + expect(rendered).to have_content('Keyword-123') + expect(rendered).to have_content('Resource-Type-123') + expect(rendered).to have_content('Rights-Statement-123') + expect(rendered).to have_content('28/05/2019') # NB: complex date is reformatted to dd/mm/yyyy + expect(rendered).to have_content('10.0.1111') + expect(rendered).to have_content('Complex-Person-123') + expect(rendered).to have_content('http://creativecommons.org/publicdomain/zero/1.0/') + expect(rendered).to have_content('Complex-Version-123') + end + end + + context 'authenticated NIMS Researcher' do + let(:user) { create(:user, :nims_researcher) } + it 'shows the correct metadata' do + expect(rendered).to have_content('Alternative-Title-123') + expect(rendered).to have_content('Subject-123') + expect(rendered).to have_content('Publisher-123') + expect(rendered).to have_content('Faroese') + expect(rendered).to have_content('Keyword-123') + expect(rendered).to have_content('Resource-Type-123') + expect(rendered).to have_content('Rights-Statement-123') + expect(rendered).to have_content('28/05/2019') # NB: complex date is reformatted to dd/mm/yyyy + expect(rendered).to have_content('10.0.1111') + expect(rendered).to have_content('Complex-Person-123') + expect(rendered).to have_content('http://creativecommons.org/publicdomain/zero/1.0/') + expect(rendered).to have_content('Complex-Version-123') + end + end +end diff --git a/hyrax/spec/views/hyrax/publications/_attribute_rows.html_spec.rb b/hyrax/spec/views/hyrax/publications/_attribute_rows.html_spec.rb new file mode 100644 index 00000000..bfe0a036 --- /dev/null +++ b/hyrax/spec/views/hyrax/publications/_attribute_rows.html_spec.rb @@ -0,0 +1,70 @@ +require 'rails_helper' +include Warden::Test::Helpers + +RSpec.describe 'hyrax/publications/_attribute_rows' do + let(:partial) { 'hyrax/publications/attribute_rows' } + let(:publication) { build(:publication, :open, :with_alternative_title, :with_people, :with_keyword, :with_subject, :with_language, + :with_publisher, :with_complex_date, :with_complex_identifier, :with_rights_statement, :with_complex_rights, + :with_complex_version, :with_resource_type, :with_source, :with_issue, :with_complex_source, :with_complex_event, + :with_place, :with_table_of_contents, :with_number_of_pages) } + let(:presenter) { Hyrax::PublicationPresenter.new(SolrDocument.new(publication.to_solr), Ability.new(user), controller.request) } + + before do + allow(controller).to receive(:current_user).and_return(user) + login_as user if user.present? + render partial: partial, locals: { presenter: presenter } + end + + # NB: the visibility of individual metadata components is set in app/models/ability.rb + # This test confirms the current expected behaviour (which is that most metadata is visible) + + context 'unauthenticated user' do + let(:user) { nil } + it 'shows the correct metadata' do + expect(rendered).to have_content('Alternative-Title-123') + expect(rendered).to have_content('Subject-123') + expect(rendered).to have_content('Publisher-123') + expect(rendered).to have_content('Faroese') + expect(rendered).to have_content('Keyword-123') + expect(rendered).to have_content('Resource-Type-123') + expect(rendered).to have_content('Rights-Statement-123') + expect(rendered).to have_content('28/05/2019') # NB: complex date is reformatted to dd/mm/yyyy + expect(rendered).to have_content('10.0.1111') + expect(rendered).to have_content('Big Baz') + expect(rendered).to have_content('http://creativecommons.org/publicdomain/zero/1.0/') + expect(rendered).to have_content('Creating the first version') + expect(rendered).to have_content('Event-Title-123') + expect(rendered).to have_content('Issue-123') + expect(rendered).to have_content('221B Baker Street Place') + expect(rendered).to have_content('Table-of-Contents-123') + expect(rendered).to have_content('Number-of-Pages-123') + expect(rendered).to have_content('Source-123') + expect(rendered).to have_content('Test journal') + end + end + + context 'authenticated NIMS Researcher' do + let(:user) { create(:user, :nims_researcher) } + it 'shows the correct metadata' do + expect(rendered).to have_content('Alternative-Title-123') + expect(rendered).to have_content('Subject-123') + expect(rendered).to have_content('Publisher-123') + expect(rendered).to have_content('Faroese') + expect(rendered).to have_content('Keyword-123') + expect(rendered).to have_content('Resource-Type-123') + expect(rendered).to have_content('Rights-Statement-123') + expect(rendered).to have_content('28/05/2019') # NB: complex date is reformatted to dd/mm/yyyy + expect(rendered).to have_content('10.0.1111') + expect(rendered).to have_content('Big Baz') + expect(rendered).to have_content('http://creativecommons.org/publicdomain/zero/1.0/') + expect(rendered).to have_content('Creating the first version') + expect(rendered).to have_content('Event-Title-123') + expect(rendered).to have_content('Issue-123') + expect(rendered).to have_content('221B Baker Street Place') + expect(rendered).to have_content('Table-of-Contents-123') + expect(rendered).to have_content('Number-of-Pages-123') + expect(rendered).to have_content('Source-123') + expect(rendered).to have_content('Test journal') + end + end +end diff --git a/hyrax/spec/views/shared/_citations.html_spec.rb b/hyrax/spec/views/shared/_citations.html_spec.rb new file mode 100644 index 00000000..6e2739c2 --- /dev/null +++ b/hyrax/spec/views/shared/_citations.html_spec.rb @@ -0,0 +1,39 @@ +require 'rails_helper' +include Warden::Test::Helpers + +RSpec.describe 'shared/_citations' do + let(:dataset) { create(:dataset, :open, :with_description_seq) } + let(:presenter) { Hyrax::DatasetPresenter.new(SolrDocument.new(dataset.to_solr), Ability.new(user), controller.request) } + + before do + allow(controller).to receive(:current_user).and_return(user) + login_as user if user.present? + assign(:presenter, presenter) + render + render inline: '<%= yield :twitter_meta %>' + end + + # This test confirms the abstract is only visible if you are logged in + describe 'og:description' do + context 'unauthenticated user' do + let(:user) { nil } + it 'does not show the abstract and shows the title instead' do + expect(rendered).to have_css("meta[property='og:description'][content='#{dataset.title.first}']", visible: false) + end + end + + context 'authenticated non-researcher' do + let(:user) { build(:user, :nims_other) } + it 'shows the abstract' do + expect(rendered).to have_css("meta[property='og:description'][content='#{dataset.description.first}']", visible: false) + end + end + + context 'authenticated NIMS Researcher' do + let(:user) { create(:user, :nims_researcher) } + it 'shows the abstract' do + expect(rendered).to have_css("meta[property='og:description'][content='#{dataset.description.first}']", visible: false) + end + end + end +end