diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..fdf344181aa2e620a74ceb60f909662c6d058f70 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,55 @@ +image: docker:stable +image: ruby:2.7.5 + +stages: + - build + - test + - deploy + +services: + - docker:dind + - postgres:13-alpine + - redis:6 + +variables: + POSTGRES_DB: 'hyrax_test' + POSTGRES_DB_TEST: 'hyrax_test' + POSTGRES_USER: 'postgres' + POSTGRES_PASSWORD: 'password' + POSTGRES_HOST_AUTH_METHOD: trust + +build-job: + stage: build + before_script: + - apt-get update -qq && apt-get install -y -qq nodejs + - cd hyrax + - bundle install --jobs 4 --retry 3 + script: + - export FITS_ROOT=~/rdms-hyrax/ + - mkdir -p ${FITS_ROOT} + - wget -q https://github.com/harvard-lts/fits/releases/download/1.5.0/fits-1.5.0.zip -O ${FITS_ROOT}/fits-1.5.0.zip + - unzip -q ${FITS_ROOT}/fits-1.5.0.zip -d ${FITS_ROOT}/fits-1.5.0 + - chmod a+x ${FITS_ROOT}/fits-1.5.0/fits.sh + - rm ${FITS_ROOT}/fits-1.5.0.zip + - bundle exec rake db:test:prepare + +test-job: + stage: test + coverage: '/coverage: \d+.\d+% of statements/' + before_script: + - apt-get update -qq && apt-get install -y -qq nodejs + - apt-get update -qq && apt-get install -y -qq software-properties-common + - apt-add-repository 'deb http://security.debian.org/debian-security stretch/updates main' + - apt-get update && apt-get -y install openjdk-8-jdk libmediainfo-dev + - update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java + - cd hyrax + - bundle install --jobs 4 --retry 3 + script: + - export FITS_PATH=~/rdms-hyrax/fits-1.3.0/fits.sh + - if test -f "lib/tasks/test_servers.rake"; then echo 'Running full tests' && bundle exec rake test:servers:start && bundle exec rspec && bundle exec rake test:servers:stop; else echo "Running limited tests"; bundle exec rspec --exclude-pattern "**/features/*_spec.rb"; fi + +deploy-job: + stage: deploy + script: + - echo "Deploying application..." + - echo "Application successfully deployed." diff --git a/README.md b/README.md index c88f355041a790be01cbf0c22818b025b0375ee0..6724d2e5b1b3b3e32cf2bcac9040b3ca7b12b480 100644 --- a/README.md +++ b/README.md @@ -26,44 +26,37 @@ You should see the containers being built and the services start. There are 2 `docker-compose` files provided in the repository, which build the containers running the services as shown above * [docker-compose.yml](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml) is the main docker-compose file. It builds all the core servcies required to run the application - - * [docker-compose.override.yml](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.override.yml) is used along with the main [docker-compose.yml](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml) file in development, mainly to expose ports for the various services. ### Containers running in docker * [fcrepo](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml#L13-L22) 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). - - + By default, this runs the fedora service on port 8080 internally in docker. + http://fcrepo:8080/fcrepo/rest * [Solr container](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml#L24-L45) 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). - - + By default, this runs the SOLR service on port 8983 internally in docker. + http://solr:8983 * [db containers](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml#L47-L76) running a postgres database for use by the Hyrax application (appdb) and Fedora (fcrepodb). By default, this runs the database service on port 5432 internally in docker. - - * [redis container](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml#L121-L132) 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://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml#L78-L96) sets up the Hyrax application, which is then used by 2 services - web and workers. * [Web container](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml#L98-L110) runs the application. - By default, this runs on port 3000 internally in docker (http://web:3000). - - This container runs [docker-entrypoint.sh](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/hyrax/docker-entrypoint.sh), on startup. The bash script - + By default, this runs on port 3000 internally in docker. + http://web:3000 + + This container runs [docker-entrypoint.sh](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/hyrax/docker-entrypoint.sh), on startup. The bash script + * creates the log folder * checks the bundle (and installs It in development) * does the database setup @@ -75,14 +68,11 @@ There are 2 `docker-compose` files provided in the repository, which build the c * Creates the default admin set and collection types * Starts the rails server - * [Wokers container](https://gitlab.ruhr-uni-bochum.de/FDM/rdm-system/rdms/-/blob/master/docker-compose.yml#L112-L119) runs the background tasks, using [sidekiq](https://github.com/mperham/sidekiq) 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 number 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. diff --git a/docker-compose.yml b/docker-compose.yml index fccdd3df77f98ac341f19d7f64401ba34286fcdc..eb4a70d97e58d027a50c480bcda22dde1bc5c415 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -166,6 +166,8 @@ services: - PHP_MEMORY_LIMIT=2048M env_file: - .env + ports: + - 9000:9000 networks: internal: aliases: diff --git a/hyrax/.gitignore b/hyrax/.gitignore index 81452db9256834c30e6e2a6881468c0b9a09eb54..02f3113a5adb271deab4ecbed24a644c3ed02a7b 100644 --- a/hyrax/.gitignore +++ b/hyrax/.gitignore @@ -16,6 +16,7 @@ /tmp/* !/log/.keep !/tmp/.keep +/fits.log # Ignore uploaded files in development /storage/* diff --git a/hyrax/Dockerfile b/hyrax/Dockerfile index ca5d1ddd9c59b74957d9c2524ae3ce941a971f7e..389e81998778303c3423c000fede8c06d9262e81 100644 --- a/hyrax/Dockerfile +++ b/hyrax/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.7-buster +FROM ruby:2.7.5-buster # Setup build variables ARG RAILS_ENV diff --git a/hyrax/Gemfile b/hyrax/Gemfile index d1dfee0b7f4ab1dc042066d22709b5bd379042c8..5da32b463b8ef7a0f0ab78929f158a5f4bff5108 100644 --- a/hyrax/Gemfile +++ b/hyrax/Gemfile @@ -15,6 +15,7 @@ gem 'sass-rails', '~> 5.0' gem 'uglifier', '>= 1.3.0' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'mini_racer', platforms: :ruby +gem 'therubyracer' # Use CoffeeScript for .coffee assets and views gem 'coffee-rails', '~> 4.2' @@ -68,6 +69,7 @@ group :development, :test do end gem 'rsolr', '>= 1.0', '< 3' +gem 'solrizer', '~> 4.1' gem 'bootstrap-sass', '~> 3.0' gem 'twitter-typeahead-rails', '0.11.1.pre.corejavascript' gem 'jquery-rails' @@ -84,4 +86,6 @@ gem 'bootstrap-datepicker-rails' gem 'pg' gem 'riiif', '~> 2.3' +gem 'rinku' gem 'coveralls', require: false +gem 'database_cleaner' diff --git a/hyrax/Gemfile.lock b/hyrax/Gemfile.lock index 9b11bbf4253ca53d7fc2d41f00c67e45ad684e4e..2425189e2366cf60538b97b67876bb498c40aadb 100644 --- a/hyrax/Gemfile.lock +++ b/hyrax/Gemfile.lock @@ -181,6 +181,12 @@ GEM thor (>= 0.19.4, < 2.0) tins (~> 1.6) crass (1.0.6) + database_cleaner (2.0.1) + database_cleaner-active_record (~> 2.0.0) + database_cleaner-active_record (2.0.1) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) declarative (0.0.20) declarative-builder (0.1.0) declarative-option (< 0.2.0) @@ -531,6 +537,7 @@ GEM rdf (~> 3.0) legato (0.7.0) multi_json + libv8 (3.16.14.19) link_header (0.0.8) linkeddata (3.2.0) json-ld (~> 3.2) @@ -732,6 +739,7 @@ GEM redis (>= 3.0.4) redlock (1.2.2) redis (>= 3.0.0, < 5.0) + ref (2.0.0) reform (2.5.0) disposable (>= 0.4.2, < 0.5.0) representable (>= 2.4.0, < 3.1.0) @@ -755,6 +763,7 @@ GEM deprecation (>= 1.0.0) iiif-image-api (>= 0.1.0) railties (>= 4.2, < 7) + rinku (2.0.6) rsolr (2.5.0) builder (>= 2.1.2) faraday (>= 0.9, < 3, != 2.0.0) @@ -842,6 +851,10 @@ GEM retriable ruby-progressbar rubyzip + solrizer (4.1.0) + activesupport + nokogiri + xml-simple sparql (3.2.1) builder (~> 3.2) ebnf (~> 2.2) @@ -878,6 +891,9 @@ GEM temple (0.8.2) term-ansicolor (1.7.1) tins (~> 1.0) + therubyracer (0.12.3) + libv8 (~> 3.16.14.15) + ref thor (1.2.1) thread_safe (0.3.6) tilt (2.0.10) @@ -929,6 +945,8 @@ GEM websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) + xml-simple (1.1.9) + rexml xpath (3.2.0) nokogiri (~> 1.8) @@ -944,6 +962,7 @@ DEPENDENCIES chromedriver-helper coffee-rails (~> 4.2) coveralls + database_cleaner devise devise-guests (~> 0.6) factory_bot_rails @@ -958,15 +977,18 @@ DEPENDENCIES rails (~> 5.2.6) redis (~> 4.0) riiif (~> 2.3) + rinku rsolr (>= 1.0, < 3) rspec-rails sass-rails (~> 5.0) selenium-webdriver sidekiq solr_wrapper (>= 0.3) + solrizer (~> 4.1) spring spring-watcher-listen (~> 2.0.0) sqlite3 (~> 1.3.0) + therubyracer turbolinks (~> 5) twitter-typeahead-rails (= 0.11.1.pre.corejavascript) tzinfo-data diff --git a/hyrax/app/actors/hyrax/actors/crc_dataset_actor.rb b/hyrax/app/actors/hyrax/actors/crc_dataset_actor.rb new file mode 100644 index 0000000000000000000000000000000000000000..d6d851776d0995e1d46ab9862802955733bcaf33 --- /dev/null +++ b/hyrax/app/actors/hyrax/actors/crc_dataset_actor.rb @@ -0,0 +1,8 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +module Hyrax + module Actors + class CrcDatasetActor < Hyrax::Actors::BaseActor + end + end +end diff --git a/hyrax/app/assets/javascripts/application.js b/hyrax/app/assets/javascripts/application.js index 40590c10450e4542b40fecf848fdb3f86c516028..800fe2aab4b30ff2295161fff885204353e261d9 100644 --- a/hyrax/app/assets/javascripts/application.js +++ b/hyrax/app/assets/javascripts/application.js @@ -1,8 +1,8 @@ // This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // -// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's -// vendor/assets/javascripts directory can be referenced here using a relative path. +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. JavaScript code in this file should be added after the last require_* statement. @@ -10,16 +10,16 @@ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // -//= -//= require activestorage -//= require turbolinks -// -// Required by Blacklight //= require jquery //= require jquery_ujs //= require dataTables/jquery.dataTables //= require dataTables/bootstrap/3/jquery.dataTables.bootstrap +//= require bootstrap-datepicker +// +// Required by Blacklight //= require blacklight/blacklight +//= require hydra-editor/editMetadata +//= require tinymce //= require_tree . //= require hyrax 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 0000000000000000000000000000000000000000..6da1cd897618e371bc5bb1470d9a6802dae2885c --- /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 0000000000000000000000000000000000000000..9e5d1c5ea5b61187c115d055dc26ee7a27b34078 --- /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: '<span class=\"input-group-btn field-controls\">', + fieldWrapperClass: '.field-wrapper', + warningClass: '.has-warning', + listClass: '.listing', + removeInputClass: '.remove-hidden', + + addHtml: '<button type=\"button\" class=\"btn btn-link add\"><span class=\"glyphicon glyphicon-plus\"></span><span class="controls-add-text"></span></button>', + addText: 'Add another', + + // removeHtml: '<button type=\"button\" class=\"btn btn-link remove\"><span class=\"glyphicon glyphicon-remove\"></span><span class="controls-remove-text"></span> <span class=\"sr-only\"> previous <span class="controls-field-name-text">field</span></span></button>', + // 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 0000000000000000000000000000000000000000..16708e528de744d039f5702d4228998c71139acb --- /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 = $("<div class=\'message has-warning\'>cannot add another with empty field</div>"); + $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/rdms.scss b/hyrax/app/assets/stylesheets/rdms.scss new file mode 100644 index 0000000000000000000000000000000000000000..b2a12769b45bc2058b0330ba524f86f31f2d64b4 --- /dev/null +++ b/hyrax/app/assets/stylesheets/rdms.scss @@ -0,0 +1,45 @@ +//-------------- colours --------------- +$rdms-grey: #F4F4F4; +$rdms-green: #AFCA0B; +$rdms-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 $rdms-green; +} + +.multi-nested .form-group, +.multi-nested .listing { + margin-bottom: 0px; +} + +.multi-nested .btn { + padding-top: 0px; +} + +.multi-nested { + margin-bottom: 1em; + background-color: $rdms-grey; + padding: 10px; +} + +form .field-wrapper label[required="required"]::after { + content: " *"; + color: red; +} + + +.custom_field .listing li:first-of-type{ + width: 100% !important; +} diff --git a/hyrax/app/controllers/catalog_controller.rb b/hyrax/app/controllers/catalog_controller.rb index 364047613e262a1c698a83a0b6a0d9dbfbd9a66d..66fc250a7e59960abca8b9b83da402910e791236 100644 --- a/hyrax/app/controllers/catalog_controller.rb +++ b/hyrax/app/controllers/catalog_controller.rb @@ -50,8 +50,8 @@ class CatalogController < ApplicationController # The ordering of the field names is the order of the display config.add_facet_field "human_readable_type_sim", label: "Type", limit: 5 config.add_facet_field "resource_type_sim", label: "Resource Type", limit: 5 - config.add_facet_field "creator_sim", limit: 5 - config.add_facet_field "contributor_sim", label: "Contributor", limit: 5 + # config.add_facet_field "creator_sim", limit: 5 + # config.add_facet_field "contributor_sim", label: "Contributor", limit: 5 config.add_facet_field "keyword_sim", limit: 5 config.add_facet_field "subject_sim", limit: 5 config.add_facet_field "language_sim", limit: 5 @@ -60,6 +60,13 @@ class CatalogController < ApplicationController config.add_facet_field "file_format_sim", limit: 5 config.add_facet_field "member_of_collection_ids_ssim", limit: 5, label: 'Collections', helper_method: :collection_title_by_id + facet_fields = (DatasetIndexer.facet_fields + + CrcDatasetIndexer.facet_fields + ).uniq + facet_fields.each do |fld| + config.add_facet_field fld, limit: 5 + end + # The generic_type and depositor are not displayed on the facet list # They are used to give a label to the filters that comes from the user profile config.add_facet_field "generic_type_sim", if: false @@ -76,8 +83,8 @@ class CatalogController < ApplicationController config.add_index_field "description_tesim", itemprop: 'description', helper_method: :iconify_auto_link config.add_index_field "keyword_tesim", itemprop: 'keywords', link_to_search: "keyword_sim" config.add_index_field "subject_tesim", itemprop: 'about', link_to_search: "subject_sim" - config.add_index_field "creator_tesim", itemprop: 'creator', link_to_search: "creator_sim" - config.add_index_field "contributor_tesim", itemprop: 'contributor', link_to_search: "contributor_sim" + # config.add_index_field "creator_tesim", itemprop: 'creator', link_to_search: "creator_sim" + # config.add_index_field "contributor_tesim", itemprop: 'contributor', link_to_search: "contributor_sim" config.add_index_field "proxy_depositor_ssim", label: "Depositor", helper_method: :link_to_profile config.add_index_field "depositor_tesim", label: "Owner", helper_method: :link_to_profile config.add_index_field "publisher_tesim", itemprop: 'publisher', link_to_search: "publisher_sim" @@ -114,6 +121,13 @@ class CatalogController < ApplicationController config.add_show_field "format_tesim" config.add_show_field "identifier_tesim" + show_fields = (DatasetIndexer.show_fields + + CrcDatasetIndexer.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 # diff --git a/hyrax/app/controllers/hyrax/crc_datasets_controller.rb b/hyrax/app/controllers/hyrax/crc_datasets_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..fb529f4eb055959e0ed5b3eae34a7349a2afa445 --- /dev/null +++ b/hyrax/app/controllers/hyrax/crc_datasets_controller.rb @@ -0,0 +1,14 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +module Hyrax + # Generated controller for CrcDataset + class CrcDatasetsController < ApplicationController + # Adds Hyrax behaviors to the controller. + include Hyrax::WorksControllerBehavior + include Hyrax::BreadcrumbsForWorks + self.curation_concern_type = ::CrcDataset + + # Use this line if you want to use a custom presenter + self.show_presenter = Hyrax::CrcDatasetPresenter + end +end diff --git a/hyrax/app/forms/hyrax/crc_dataset_form.rb b/hyrax/app/forms/hyrax/crc_dataset_form.rb new file mode 100644 index 0000000000000000000000000000000000000000..1e1407a79da21d5d13dcf3108d2288b485404c4c --- /dev/null +++ b/hyrax/app/forms/hyrax/crc_dataset_form.rb @@ -0,0 +1,147 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +module Hyrax + # Generated form for CrcDataset + class CrcDatasetForm < Hyrax::Forms::WorkForm + self.model_class = ::CrcDataset + self.terms -= [ + # Fields not interested in + :creator, :contributor, :rights_notes, :rights_statement, + :access_right, :date_created, :identifier, :based_near, :related_url, :source, + # Fields interested in, but removing to re-order + :title, :alternative_title, :resource_type, :description, :abstract, :keyword, :license, + :publisher, :subject, :language, + # Fields that are not displayed + # :import_url, :date_modified, :date_uploaded, :depositor, :bibliographic_citation, :label, :relative_path + ] + + self.terms += [ + # Adding all fields in order of display in form + :doi, + :title, + :alternative_title, + :complex_person, + :abstract, + :description, + :complex_identifier, + :complex_date, + :modality, + :complex_subject, + :approval_number, + :keyword, + :crc_resource_type, + :subject, + :publisher, + :language, + :complex_funding_reference, + :complex_relation, + :software_version, + :extra_information + ] + + self.required_fields -= [ + # Fields not interested in + :creator, :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, :complex_person, :abstract, :keyword, :crc_resource_type, :license + ] + + 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, + :corresponding_author, + :display_order, + { + last_name: [], + first_name: [], + name: [], + role: [], + orcid: [], + affiliation: [], + } + ] + end + + def self.permitted_relation_params + [:id, + :_destroy, + { + title: [], + url: [], + complex_identifier_attributes: permitted_identifier_params, + relationship: [] + } + ] + end + + def self.permitted_fundref_params + [:id, + :_destroy, + { + funder_identifier: [], + funder_name: [], + award_number: [], + award_uri: [], + award_title: [] + } + ] + end + + def self.permitted_subject_params + [:id, + :_destroy, + { + subject_identifier: [], + subject_species: [], + subject_type: [], + subject_sex: [], + subject_age: [], + } + ] + end + + def self.build_permitted_params + permitted = super + permitted << :doi + permitted << :modality + permitted << :crc_resource_type + permitted << :approval_number + permitted << :extra_information + permitted << :software_version + permitted << { complex_date_attributes: permitted_date_params } + permitted << { complex_identifier_attributes: permitted_identifier_params } + permitted << { complex_person_attributes: permitted_person_params } + permitted << { complex_relation_attributes: permitted_relation_params } + permitted << { complex_funding_reference_attributes: permitted_fundref_params } + permitted << { complex_subject_attributes: permitted_subject_params } + end + end +end diff --git a/hyrax/app/forms/hyrax/dataset_form.rb b/hyrax/app/forms/hyrax/dataset_form.rb index ff6de5d22c9f0e4ef423b2e6e644243a5aeb1ea4..a6e4a731b23561b1cce324454acff9dc38e09e6d 100644 --- a/hyrax/app/forms/hyrax/dataset_form.rb +++ b/hyrax/app/forms/hyrax/dataset_form.rb @@ -4,6 +4,121 @@ module Hyrax # Generated form for Dataset class DatasetForm < Hyrax::Forms::WorkForm self.model_class = ::Dataset - self.terms += [:resource_type] + + self.terms -= [ + # Fields not interested in + :creator, :contributor, :rights_notes, :rights_statement, + :access_right, :date_created, :identifier, :based_near, :related_url, :source, + # Fields interested in, but removing to re-order + :title, :alternative_title, :resource_type, :description, :abstract, :keyword, :license, + :publisher, :subject, :language, + # Fields that are not displayed + # :import_url, :date_modified, :date_uploaded, :depositor, :bibliographic_citation, :label, :relative_path + ] + + self.terms += [ + # Adding all fields in order of display in form + :doi, + :title, + :alternative_title, + :complex_person, + :resource_type, + :abstract, + :description, + :keyword, + :subject, + :publisher, + :language, + :complex_date, + :complex_identifier, + :complex_funding_reference, + :complex_relation, + ] + + self.required_fields -= [ + # Fields not interested in + :creator, :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, :complex_person, :abstract, :keyword, :license + ] + + 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, + :corresponding_author, + :display_order, + { + last_name: [], + first_name: [], + name: [], + role: [], + orcid: [], + affiliation: [], + } + ] + end + + def self.permitted_relation_params + [:id, + :_destroy, + { + title: [], + url: [], + complex_identifier_attributes: permitted_identifier_params, + relationship: [] + } + ] + end + + def self.permitted_fundref_params + [:id, + :_destroy, + { + funder_identifier: [], + funder_name: [], + award_number: [], + award_uri: [], + award_title: [] + } + ] + end + + def self.build_permitted_params + permitted = super + permitted << :doi + permitted << { complex_date_attributes: permitted_date_params } + permitted << { complex_identifier_attributes: permitted_identifier_params } + permitted << { complex_person_attributes: permitted_person_params } + permitted << { complex_relation_attributes: permitted_relation_params } + permitted << { complex_funding_reference_attributes: permitted_fundref_params } + 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 0000000000000000000000000000000000000000..0753f9c445cf570dc811923c9da8d2e695bab264 --- /dev/null +++ b/hyrax/app/indexers/complex_field/date_indexer.rb @@ -0,0 +1,113 @@ +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('ï¼-ï¼™ï½-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('ï¼-ï¼™ï½-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') } unless dates.blank? + 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('ï¼-ï¼™ï½-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('ï¼-ï¼™ï½-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/fundref_indexer.rb b/hyrax/app/indexers/complex_field/fundref_indexer.rb new file mode 100644 index 0000000000000000000000000000000000000000..59581bf196baa4666e92f3542229c7a43ce06a27 --- /dev/null +++ b/hyrax/app/indexers/complex_field/fundref_indexer.rb @@ -0,0 +1,54 @@ +module ComplexField + module FundrefIndexer + def generate_solr_document + super.tap do |solr_doc| + index_fundref(solr_doc) + end + end + + def index_fundref(solr_doc) + # funding reference object in json + fld_name = Solrizer.solr_name('complex_funding_reference', :displayable) + solr_doc[fld_name] = object.complex_funding_reference.to_json + # funder_identifier - symbol + fld_name = Solrizer.solr_name('funder_identifier', :symbol) + solr_doc[fld_name] = object.complex_funding_reference.map { |r| r.funder_identifier.reject(&:blank?).first } + # funder_name - searchable + fld_name = Solrizer.solr_name('funder', :stored_searchable) + solr_doc[fld_name] = object.complex_funding_reference.map { |r| r.funder_name.reject(&:blank?).first } + # funder_name - facetable + fld_name = Solrizer.solr_name('funder', :facetable) + solr_doc[fld_name] = object.complex_funding_reference.map { |r| r.funder_name.reject(&:blank?).first } + # award_number - symbol + fld_name = Solrizer.solr_name('award_number', :symbol) + solr_doc[fld_name] = object.complex_funding_reference.map { |r| r.award_number.reject(&:blank?).first } + # award_title - searchable + fld_name = Solrizer.solr_name('award_title', :stored_searchable) + solr_doc[fld_name] = object.complex_funding_reference.map { |r| r.award_title.reject(&:blank?).first } + end + + def self.fundref_facet_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('funder', :facetable) + fields + end + + def self.fundref_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('funder_identifier', :symbol) + fields << Solrizer.solr_name('funder', :stored_searchable) + fields << Solrizer.solr_name('award_number', :symbol) + fields << Solrizer.solr_name('award_title', :stored_searchable) + fields + end + + def self.fundref_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_funding_reference', :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 0000000000000000000000000000000000000000..5d01be90bffc7d8d9420a3725c84ac7eef0a4cdc --- /dev/null +++ b/hyrax/app/indexers/complex_field/identifier_indexer.rb @@ -0,0 +1,52 @@ +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 + facetable_ids = %w(group_id project_id) + object.complex_identifier.each do |i| + unless i.scheme.blank? || i.identifier.blank? + label = i.scheme.reject(&:blank?).first.downcase.tr(' ', '_') + fld_name = Solrizer.solr_name("complex_identifier_#{label}", :symbol) + solr_doc[fld_name] = [] unless solr_doc.include?(fld_name) + solr_doc[fld_name] << i.identifier.reject(&:blank?) + solr_doc[fld_name].flatten! + if facetable_ids.include?(label) + fld_name = Solrizer.solr_name("complex_identifier_#{label}", :facetable) + 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 + end + + def self.identifier_facet_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_identifier_group_id', :facetable) + fields << Solrizer.solr_name('complex_identifier_project_id', :facetable) + fields + 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/person_indexer.rb b/hyrax/app/indexers/complex_field/person_indexer.rb new file mode 100644 index 0000000000000000000000000000000000000000..8d97de84e1b12ea134eefb0837be7ca450c771e2 --- /dev/null +++ b/hyrax/app/indexers/complex_field/person_indexer.rb @@ -0,0 +1,84 @@ +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 = RoleService.new.label(c.role.first) unless c.role.blank? + label = label.downcase.tr(' ', '_') + # 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.orcid.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 + vals = c.affiliation.reject(&:blank?) + fld_name = Solrizer.solr_name('complex_person_affiliation', :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_affiliation', :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 + + 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_operator', :facetable) + fields << Solrizer.solr_name('complex_person_contact_person', :facetable) + fields << Solrizer.solr_name('complex_person_affiliation', :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_identifier', :symbol) + fields << Solrizer.solr_name('complex_person_affiliation', :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/relation_indexer.rb b/hyrax/app/indexers/complex_field/relation_indexer.rb new file mode 100644 index 0000000000000000000000000000000000000000..52b158abc4678a93e0bfd98d8a0422c00ac2e9ed --- /dev/null +++ b/hyrax/app/indexers/complex_field/relation_indexer.rb @@ -0,0 +1,40 @@ +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? || only_blank_strings?(r.relationship) + 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 + + ## + # If the complex relation is only an array of blank strings, it doesn't need to be indexed + # @return [Boolean] + def only_blank_strings?(relationship) + relationship.delete("") + relationship.empty? + end + end +end diff --git a/hyrax/app/indexers/complex_field/subject_indexer.rb b/hyrax/app/indexers/complex_field/subject_indexer.rb new file mode 100644 index 0000000000000000000000000000000000000000..9916f7745c2197941c06a66ca13f6c0fcb258069 --- /dev/null +++ b/hyrax/app/indexers/complex_field/subject_indexer.rb @@ -0,0 +1,89 @@ +module ComplexField + module SubjectIndexer + def generate_solr_document + super.tap do |solr_doc| + index_subject(solr_doc) + end + end + + def index_subject(solr_doc) + solr_doc[Solrizer.solr_name('complex_subject', :displayable)] = object.complex_subject.to_json + object.complex_subject.each do |c| + # identifier + fld_name = Solrizer.solr_name('complex_subject_id', :symbol) + vals = c.subject_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 + # species + vals = c.subject_species.reject(&:blank?) + fld_name = Solrizer.solr_name('complex_subject_species', :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_subject_species', :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 + # type + vals = c.subject_type.reject(&:blank?) + fld_name = Solrizer.solr_name('complex_subject_type', :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_subject_type', :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 + # sex + vals = c.subject_sex.reject(&:blank?) + fld_name = Solrizer.solr_name('complex_subject_sex', :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_subject_sex', :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 + # age + vals = c.subject_age.reject(&:blank?) + fld_name = Solrizer.solr_name('complex_subject_age', :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_subject_age', :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 + + def self.subject_facet_fields + # solr fields that will be treated as facets + fields = [] + fields << Solrizer.solr_name('complex_subject_species', :facetable) + fields << Solrizer.solr_name('complex_subject_type', :facetable) + fields << Solrizer.solr_name('complex_subject_sex', :facetable) + fields << Solrizer.solr_name('complex_subject_age', :facetable) + fields + end + + def self.subject_search_fields + # solr fields that will be used for a search + fields = [] + fields << Solrizer.solr_name('complex_subject_identifier', :symbol) + fields << Solrizer.solr_name('complex_subject_species', :stored_searchable) + fields << Solrizer.solr_name('complex_subject_type', :stored_searchable) + fields << Solrizer.solr_name('complex_subject_sex', :stored_searchable) + fields << Solrizer.solr_name('complex_subject_age', :stored_searchable) + fields + end + + def self.subject_show_fields + # solr fields that will be used to display results on the record page + fields = [] + fields << Solrizer.solr_name('complex_subject', :displayable) + fields + end + end +end diff --git a/hyrax/app/indexers/crc_dataset_indexer.rb b/hyrax/app/indexers/crc_dataset_indexer.rb new file mode 100644 index 0000000000000000000000000000000000000000..8d9511d27562000e60d61a91467228b072075c76 --- /dev/null +++ b/hyrax/app/indexers/crc_dataset_indexer.rb @@ -0,0 +1,55 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +class CrcDatasetIndexer < RdmsIndexer + # 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 + + # Custom indexers for crc dataset model + include ComplexField::PersonIndexer + include ComplexField::DateIndexer + include ComplexField::IdentifierIndexer + include ComplexField::FundrefIndexer + include ComplexField::RelationIndexer + include ComplexField::SubjectIndexer + + def self.facet_fields + # solr fields that will be treated as facets + super.tap do |fields| + fields << Solrizer.solr_name('modality', :facetable) + fields.concat ComplexField::IdentifierIndexer.identifier_facet_fields + fields.concat ComplexField::DateIndexer.date_facet_fields + fields.concat ComplexField::PersonIndexer.person_facet_fields + fields.concat ComplexField::FundrefIndexer.fundref_facet_fields + fields.concat ComplexField::SubjectIndexer.subject_facet_fields + end + end + + def self.search_fields + # solr fields that will be used for a search + super.tap do |fields| + fields << Solrizer.solr_name('modality', :stored_searchable) + fields.concat ComplexField::IdentifierIndexer.identifier_search_fields + fields.concat ComplexField::DateIndexer.date_search_fields + fields.concat ComplexField::PersonIndexer.person_search_fields + fields.concat ComplexField::FundrefIndexer.fundref_search_fields + fields.concat ComplexField::SubjectIndexer.subject_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| + fields << Solrizer.solr_name('modality', :stored_searchable) + fields.concat ComplexField::IdentifierIndexer.identifier_show_fields + fields.concat ComplexField::DateIndexer.date_show_fields + fields.concat ComplexField::PersonIndexer.person_show_fields + fields.concat ComplexField::FundrefIndexer.fundref_show_fields + fields.concat ComplexField::SubjectIndexer.subject_show_fields + end + end +end diff --git a/hyrax/app/indexers/dataset_indexer.rb b/hyrax/app/indexers/dataset_indexer.rb index f7a770b564af75f4175c5bbcd8b71bded0a530a8..c7b9369bb275c7097f94f57a07fea28b6271b3a9 100644 --- a/hyrax/app/indexers/dataset_indexer.rb +++ b/hyrax/app/indexers/dataset_indexer.rb @@ -1,6 +1,6 @@ # Generated via # `rails generate hyrax:work Dataset` -class DatasetIndexer < Hyrax::WorkIndexer +class DatasetIndexer < RdmsIndexer # This indexes the default metadata. You can remove it if you want to # provide your own metadata and indexing. include Hyrax::IndexesBasicMetadata @@ -9,10 +9,40 @@ class DatasetIndexer < Hyrax::WorkIndexer # 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 + # Custom indexers for dataset model + include ComplexField::PersonIndexer + include ComplexField::DateIndexer + include ComplexField::IdentifierIndexer + include ComplexField::FundrefIndexer + include ComplexField::RelationIndexer + + def self.facet_fields + # solr fields that will be treated as facets + super.tap do |fields| + fields.concat ComplexField::DateIndexer.date_facet_fields + fields.concat ComplexField::PersonIndexer.person_facet_fields + fields.concat ComplexField::FundrefIndexer.fundref_facet_fields + end + end + + def self.search_fields + # solr fields that will be used for a search + super.tap do |fields| + fields.concat ComplexField::IdentifierIndexer.identifier_search_fields + fields.concat ComplexField::DateIndexer.date_search_fields + fields.concat ComplexField::PersonIndexer.person_search_fields + fields.concat ComplexField::FundrefIndexer.fundref_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| + fields.concat ComplexField::IdentifierIndexer.identifier_show_fields + fields.concat ComplexField::DateIndexer.date_show_fields + fields.concat ComplexField::PersonIndexer.person_show_fields + fields.concat ComplexField::FundrefIndexer.fundref_show_fields + end + end + end diff --git a/hyrax/app/indexers/rdms_indexer.rb b/hyrax/app/indexers/rdms_indexer.rb new file mode 100644 index 0000000000000000000000000000000000000000..3f9617f436866fa6c63df0aadd46ea7c9424132e --- /dev/null +++ b/hyrax/app/indexers/rdms_indexer.rb @@ -0,0 +1,85 @@ +class RdmsIndexer < 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), + # Solrizer.solr_name('visibility', :stored_sortable), + ] + 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_published', :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), + # Solrizer.solr_name('licensed_date', :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_published', :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), + # Solrizer.solr_name('licensed_date', :stored_searchable) + ] + end +end diff --git a/hyrax/app/indexers/work_indexer.rb b/hyrax/app/indexers/work_indexer.rb new file mode 100644 index 0000000000000000000000000000000000000000..372fe6974af7887f1fcfb0e13bd843e61fd172fa --- /dev/null +++ b/hyrax/app/indexers/work_indexer.rb @@ -0,0 +1,5 @@ +# Generated via +# `rails generate hyrax:work Work` +class WorkIndexer < RdmsIndexer + # Add custom indexers for work model +end diff --git a/hyrax/app/inputs/nested_attributes_input.rb b/hyrax/app/inputs/nested_attributes_input.rb new file mode 100644 index 0000000000000000000000000000000000000000..edc07cde743e4e5a857ae3c69115a1fe6ba005c8 --- /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 + " <ul class=\"inner-listing\">\n #{yield}\n </ul>\n" + end + + def nested_inner_wrapper + <<-HTML + <li class="field-wrapper"> + #{yield} + </li> + 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 << " <button type=\"button\" class=\"btn btn-link remove\">" + out << " <span class=\"glyphicon glyphicon-remove\"></span>" + out << " <span class=\"controls-remove-text\">Remove</span>" + out << " <span class=\"sr-only\"> previous <span class=\"controls-field-name-text\"> #{field_label}</span></span>" + out << " </button>" + 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_date_input.rb b/hyrax/app/inputs/nested_date_input.rb new file mode 100644 index 0000000000000000000000000000000000000000..cfe3aeda750d11027e13860eaacf28036cf7b828 --- /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 << "<div class='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 + date_options = DateService.new.select_all_options + out << " <div class='col-md-3'>" + 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 << ' </div>' + + # --- 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 << " <div class='col-md-6'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, + data: { provide: 'datepicker' }, required: required)) + out << ' </div>' + + # --- delete checkbox + if repeats == true + field_label = 'Date' + out << " <div class='col-md-3'>" + out << destroy_widget(attribute_name, index, field_label, parent) + out << ' </div>' + end + + out << '</div>' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_funding_reference_input.rb b/hyrax/app/inputs/nested_funding_reference_input.rb new file mode 100644 index 0000000000000000000000000000000000000000..732dc155b8a9e9ec2a0be12c38af809e627e643a --- /dev/null +++ b/hyrax/app/inputs/nested_funding_reference_input.rb @@ -0,0 +1,115 @@ +class NestedFundingReferenceInput < 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_funding_reference) and index == 0 + required = true + end + + # Add remove element only if element repeats + repeats = options.delete(:repeats) + repeats = true if repeats.nil? + + # --- funder identifier + field = :funder_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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << ' </div>' + out << '</div>' # row + + # --- funder name + field = :funder_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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << ' </div>' + out << '</div>' # row + + # --- award number + field = :award_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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << ' </div>' + out << '</div>' # row + + # --- award uri + field = :award_uri + 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << ' </div>' + out << '</div>' # row + + # last row + out << "<div class='row'>" + + # --- award title + field = :award_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 << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: false) + out << ' </div>' + + out << " <div class='col-md-6'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id)) + out << ' </div>' + + # --- delete checkbox + if repeats == true + field_label = 'Additional funding reference' + out << " <div class='col-md-3'>" + out << destroy_widget(attribute_name, index, field_label, parent) + out << ' </div>' + end + + out << '</div>' # 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 0000000000000000000000000000000000000000..aaf3b05ab510e1ca4d72b963dd9ab74648a4f4b4 --- /dev/null +++ b/hyrax/app/inputs/nested_identifier_input.rb @@ -0,0 +1,55 @@ +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 << "<div class='row'>" + + scheme_field = :scheme + scheme_field_name = name_for(attribute_name, index, scheme_field, parent) + scheme_field_id = id_for(attribute_name, index, scheme_field, parent) + scheme_field_value = value.send(scheme_field).first + + identifier_field = :identifier + identifier_field_name = name_for(attribute_name, index, identifier_field, parent) + identifier_field_id = id_for(attribute_name, index, identifier_field, parent) + identifier_field_value = value.send(identifier_field).first + # --- scheme + id_options = IdentifierService.new.select_all_options + out << " <div class='col-md-3'>" + out << template.select_tag(scheme_field_name, + template.options_for_select(id_options, scheme_field_value), + label: '', class: 'select form-control', prompt: 'choose type', id: scheme_field_id) + out << ' </div>' + + # --- identifier + out << " <div class='col-md-6'>" + out << @builder.text_field(identifier_field_name, + options.merge(value: identifier_field_value, name: identifier_field_name, id: identifier_field_id, + required: required)) + out << ' </div>' + + # --- delete checkbox + if repeats == true + out << " <div class='col-md-3'>" + out << destroy_widget(attribute_name, index, 'Identifier', parent) + out << ' </div>' + end + + out << '</div>' # 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 0000000000000000000000000000000000000000..cf9aa3e382a4c189637910e2f95c41ca8fbd7575 --- /dev/null +++ b/hyrax/app/inputs/nested_person_input.rb @@ -0,0 +1,134 @@ +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] + + # --- last_name + field = :last_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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, I18n.t('rdms.fields.last_name'), required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "Alphabets")) + out << ' </div>' + out << '</div>' # row + + # --- first_name + field = :first_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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, I18n.t('rdms.fields.first_name'), required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "Alphabets")) + out << ' </div>' + out << '</div>' # row + + # --- 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, I18n.t('rdms.fields.full_name'), required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "SURNAME, Given Names")) + out << ' </div>' + out << '</div>' # 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + 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 << ' </div>' + out << '</div>' # row + + # --- orcid + field = :orcid + 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "https://orcid.org/0000-0000-0000-0000")) + out << ' </div>' + out << '</div>' # row + + # --- affiliation + field = :affiliation + 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "affiliation")) + out << ' </div>' + out << '</div>' # row + + if repeats == true + field_label = 'Person' + out << "<div class='row'>" + out << " <div class='col-md-3'>" + out << destroy_widget(attribute_name, index, field_label, parent) + out << ' </div>' + out << '</div>' # 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 0000000000000000000000000000000000000000..352ff8a953a2b14df3b7a9695153f447ac6c8f2d --- /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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, 'Title', required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << ' </div>' + out << '</div>' # 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, field.to_s.humanize, required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required)) + out << ' </div>' + out << '</div>' # 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 << "<div class='row'>" + # out << " <div class='col-md-3'>" + # out << template.label_tag(field_name, field.to_s.humanize, required: false) + # out << ' </div>' + + # out << " <div class='col-md-9'>" + # out << @builder.text_field(field_name, + # options.merge(value: field_value, name: field_name, id: field_id, required: false)) + # out << ' </div>' + # out << '</div>' # row + + # last row + out << "<div class='row'>" + + # --- 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 << " <div class='col-md-3'>" + out << template.label_tag(field_name, 'Relationship', required: required) + out << ' </div>' + + out << " <div class='col-md-6'>" + 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 << ' </div>' + + # --- delete checkbox + field_label ='Related work' + out << " <div class='col-md-3'>" + out << destroy_widget(attribute_name, index, field_label, parent) + out << ' </div>' + + out << '</div>' # last row + out + end +end diff --git a/hyrax/app/inputs/nested_subject_input.rb b/hyrax/app/inputs/nested_subject_input.rb new file mode 100644 index 0000000000000000000000000000000000000000..30a22afb6d6458c12508670e64917f91d75969fb --- /dev/null +++ b/hyrax/app/inputs/nested_subject_input.rb @@ -0,0 +1,116 @@ +class NestedSubjectInput < 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_subject) 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] + + # --- identifier + field = :subject_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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, I18n.t('rdms.fields.complex_subject_identifier'), required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "identifier")) + out << ' </div>' + out << '</div>' # row + + # --- species + field = :subject_species + 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, I18n.t('rdms.fields.complex_subject_species'), required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "species")) + out << ' </div>' + out << '</div>' # row + + # --- type + field = :subject_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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, I18n.t('rdms.fields.complex_subject_type'), required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "type")) + out << ' </div>' + out << '</div>' # row + + # --- sex + field = :subject_sex + 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, I18n.t('rdms.fields.complex_subject_sex'), required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "sex")) + out << ' </div>' + out << '</div>' # row + + # --- age + field = :subject_age + 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 << "<div class='row'>" + out << " <div class='col-md-3'>" + out << template.label_tag(field_name, I18n.t('rdms.fields.complex_subject_age'), required: required) + out << ' </div>' + + out << " <div class='col-md-9'>" + out << @builder.text_field(field_name, + options.merge(value: field_value, name: field_name, id: field_id, required: required, placeholder: "age")) + out << ' </div>' + out << '</div>' # row + + if repeats == true + field_label = 'Subject' + out << "<div class='row'>" + out << " <div class='col-md-3'>" + out << destroy_widget(attribute_name, index, field_label, parent) + out << ' </div>' + out << '</div>' # last row + end + + out + end +end diff --git a/hyrax/app/models/ability.rb b/hyrax/app/models/ability.rb index 43ef51e588871cd97e1ac54465abf0425f49139d..f413b0d8b202b45a1f691672f4ac222fbcfd5521 100644 --- a/hyrax/app/models/ability.rb +++ b/hyrax/app/models/ability.rb @@ -28,6 +28,6 @@ class Ability def create_content # everyone who is logged in can create content # return unless registered_user? - can :create, ::Dataset if current_user + can :create, [::Dataset, ::CrcDataset] if current_user 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 0000000000000000000000000000000000000000..2bbfa4bfebc11a42d2d501271aad97e5789d9758 --- /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_date.rb b/hyrax/app/models/concerns/complex_date.rb new file mode 100644 index 0000000000000000000000000000000000000000..8154f5161d0fa6a3ad991767556495a2a63039e9 --- /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::DWC.eventDate + property :description, predicate: ::RDF::Vocab::DC.description + + ## 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 \ No newline at end of file diff --git a/hyrax/app/models/concerns/complex_funding_reference.rb b/hyrax/app/models/concerns/complex_funding_reference.rb new file mode 100644 index 0000000000000000000000000000000000000000..d59e8d1fef14ade5e446769a55c5c8100fcf0ee6 --- /dev/null +++ b/hyrax/app/models/concerns/complex_funding_reference.rb @@ -0,0 +1,19 @@ +class ComplexFundingReference < ActiveTriples::Resource + include CommonMethods + configure type: ::RDF::Vocab::Rdms.FundingReference + property :funder_identifier, predicate: ::RDF::Vocab::Rdms.funderIdentifier + property :funder_name, predicate: ::RDF::Vocab::Rdms.funderName + property :award_number, predicate: ::RDF::Vocab::Rdms.awardNumber + property :award_uri, predicate: ::RDF::Vocab::Rdms.awardURI + property :award_title, predicate: ::RDF::Vocab::Rdms.awardTitle + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#fundref#{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 0000000000000000000000000000000000000000..77e8c25038d7579470ca8da199b01c9007305e80 --- /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_person.rb b/hyrax/app/models/concerns/complex_person.rb new file mode 100644 index 0000000000000000000000000000000000000000..d8d3ff687dbdb7c2e8acc80646b7c86bfded13ff --- /dev/null +++ b/hyrax/app/models/concerns/complex_person.rb @@ -0,0 +1,24 @@ +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 :orcid, predicate: ::RDF::Vocab::DataCite.hasIdentifier + property :affiliation, predicate: ::RDF::Vocab::VMD.affiliation + property :display_order, predicate: ::RDF::Vocab::Rdms.order, multiple: false + + ## 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_relation.rb b/hyrax/app/models/concerns/complex_relation.rb new file mode 100644 index 0000000000000000000000000000000000000000..336680e1f32fe7c69ed99bbe667c00e1f712b797 --- /dev/null +++ b/hyrax/app/models/concerns/complex_relation.rb @@ -0,0 +1,23 @@ +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 + property :relationship, predicate: ::RDF::Vocab::EBUCore.roleType + + ## 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_subject.rb b/hyrax/app/models/concerns/complex_subject.rb new file mode 100644 index 0000000000000000000000000000000000000000..dfc9ff211e28da4084f00122f7a5123231399704 --- /dev/null +++ b/hyrax/app/models/concerns/complex_subject.rb @@ -0,0 +1,21 @@ +class ComplexSubject < ActiveTriples::Resource + include CommonMethods + + configure type: ::RDF::Vocab::Rdms.Subject + property :subject_identifier, predicate: ::RDF::Vocab::Rdms.subjectIdentifier + property :subject_species, predicate: ::RDF::Vocab::Rdms.subjectSpecies + property :subject_type, predicate: ::RDF::Vocab::Rdms.subjectType + property :subject_sex, predicate: ::RDF::Vocab::Rdms.subjectSex + property :subject_age, predicate: ::RDF::Vocab::Rdms.subjectAge + + ## Necessary to get AT to create hash URIs. + def initialize(uri, parent) + if uri.try(:node?) + uri = RDF::URI("#subject#{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 0000000000000000000000000000000000000000..6d9f3557e99709bd2d4b2467b81c5d4bbdbda7c9 --- /dev/null +++ b/hyrax/app/models/concerns/complex_validation.rb @@ -0,0 +1,76 @@ +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 + + # 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 + + # date_blank + # Requires date + resource_class.send(:define_method, :date_blank) do |attributes| + return true if attributes.blank? + get_val_blank(attributes, :date) + 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 + + # funding reference blank + # Require one of the fields to be filled in + resource_class.send(:define_method, :fundref_blank) do |attributes| + return true if attributes.blank? + id_blank = get_val_blank(attributes, :funder_identifier) + name_blank = get_val_blank(attributes, :funder_name) + award_number_blank = get_val_blank(attributes, :award_number) + award_uri_blank = get_val_blank(attributes, :award_uri) + award_title_blank = get_val_blank(attributes, :award_title) + id_blank && name_blank && award_number_blank && award_uri_blank && award_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 + + # 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 + + end +end \ No newline at end of file diff --git a/hyrax/app/models/concerns/datacite_metadata.rb b/hyrax/app/models/concerns/datacite_metadata.rb new file mode 100644 index 0000000000000000000000000000000000000000..2e798bd9a360d053d33acd2d361120cd81ab62d6 --- /dev/null +++ b/hyrax/app/models/concerns/datacite_metadata.rb @@ -0,0 +1,29 @@ +module DataciteMetadata + property :doi, predicate: ::RDF::Vocab::DataCite.doi, multiple: false do |index| + index.as :symbol + end + + property :complex_person, predicate: ::RDF::Vocab::SIOC.has_creator, class_name:"ComplexPerson" + + # property :date_published, predicate: ::RDF::Vocab::Rdms.datePublished, multiple: false do |index| + # index.type :date + # index.as :stored_sortable + # end + + property :complex_date, predicate: ::RDF::Vocab::DC.date, class_name:"ComplexDate" + + property :complex_identifier, predicate: ::RDF::Vocab::Rdms.identifier, class_name:"ComplexIdentifier" + + # Geolocation - would this be used? Ignoring for now. + + property :complex_funding_reference, predicate: ::RDF::Vocab::DataCite.fundref, class_name:"ComplexFundingReference" + + property :complex_relation, predicate: ::RDF::Vocab::DC.relation, class_name:"ComplexRelation" + + include ComplexValidation + accepts_nested_attributes_for :complex_person, reject_if: :person_blank, allow_destroy: true + 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_funding_reference, reject_if: :fundref_blank, allow_destroy: true + accepts_nested_attributes_for :complex_relation, reject_if: :relation_blank, allow_destroy: true +end \ No newline at end of file diff --git a/hyrax/app/models/crc_dataset.rb b/hyrax/app/models/crc_dataset.rb new file mode 100644 index 0000000000000000000000000000000000000000..d0e93d366fb39fb78b142d1cc93c62144034984e --- /dev/null +++ b/hyrax/app/models/crc_dataset.rb @@ -0,0 +1,109 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +class CrcDataset < ActiveFedora::Base + include ::Hyrax::WorkBehavior + + self.indexer = CrcDatasetIndexer + # Change this to restrict which works can be added as a child. + # self.valid_child_concerns = [] + validates :title, presence: { message: 'Your CRC dataset must have a title.' } + + # ------ properties from core metadata ------ + # property date_modified - not displayed (filled in by the system) + # property date_uploaded - not displayed (filled in by the system) + # property depositor - not displayed (filled in by the system) + # property title - keep + + # ------ properties from basic metadata ------ + # property alternative_title - keep + # property label - not displayed, used for file version label + # property relative_path - not displayed, used for file storage + # property import_url - not displayed, used for file imports + # property resource_type - keep + # property creator - do not display + # property contributor - do not display + # property description - keep + # property abstract - keep + # property keyword - keep + # property license - keep + # property rights_notes - do not display + # property rights_statement - do not display + # property access_right - do not display + # property publisher - keep + # property date_created - do not display + # property subject - keep + # property language - keep + # property identifier - do not display (used to store alternate identifiers) + # property based_near - do not display + # property related_url - do not display + # property bibliographic_citation - not displayed (generated by the system) + # property source - do not display (should be filled in by the system for bulk imports) + + # ------ properties from Datacite metadata ------ + property :doi, predicate: ::RDF::Vocab::DataCite.doi, multiple: false do |index| + index.as :symbol + end + + property :complex_person, predicate: ::RDF::Vocab::SIOC.has_creator, class_name:"ComplexPerson" + + # property :date_published, predicate: ::RDF::Vocab::Rdms.datePublished, multiple: false do |index| + # index.type :date + # index.as :stored_sortable + # end + + property :complex_date, predicate: ::RDF::Vocab::DC.date, class_name:"ComplexDate" + + property :complex_identifier, predicate: ::RDF::Vocab::Rdms.identifier, class_name:"ComplexIdentifier" + + # size and format to be obtained from the files attached + + # label property in basic metadata can be used for version label + + # description and abstract is in the basic metadata. Ignoring other descriptions for now. + + # Geolocation - would this be used? Ignoring for now. + + property :complex_funding_reference, predicate: ::RDF::Vocab::DataCite.fundref, class_name:"ComplexFundingReference" + + property :complex_relation, predicate: ::RDF::Vocab::DC.relation, class_name:"ComplexRelation" + + + # ------ properties from CRC metadata ------ + property :crc_resource_type, predicate: ::RDF::Vocab::Rdms.crcResourceType, multiple: false do |index| + index.as :stored_searchable, :facetable + end + + property :modality, predicate: ::RDF::Vocab::Rdms.modality, multiple: false do |index| + index.as :stored_searchable, :facetable + end + + property :complex_subject, predicate: ::RDF::Vocab::Rdms.subject, class_name:"ComplexSubject" + + property :approval_number, predicate: ::RDF::Vocab::Rdms.approvalNumber, multiple: false do |index| + index.as :symbol + end + + property :extra_information, predicate: ::RDF::Vocab::Rdms.extraInformation do |index| + index.as :stored_searchable + end + + property :software_version, predicate: ::RDF::Vocab::Rdms.softwareVersion do |index| + index.as :stored_searchable + end + + # ------ properties from DublinCore metadata ------ + property :coverage, predicate: ::RDF::Vocab::DC.coverage do |index| + index.as :stored_searchable + end + + # 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_person, reject_if: :person_blank, allow_destroy: true + 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_funding_reference, reject_if: :fundref_blank, allow_destroy: true + accepts_nested_attributes_for :complex_relation, reject_if: :relation_blank, allow_destroy: true + accepts_nested_attributes_for :complex_subject, reject_if: :all_blank, allow_destroy: true +end diff --git a/hyrax/app/models/dataset.rb b/hyrax/app/models/dataset.rb index 836578cae2f63cbfab84ac1a784f2654aa860f43..17ca0c228aa7253882f2190fe4db46d68410e520 100644 --- a/hyrax/app/models/dataset.rb +++ b/hyrax/app/models/dataset.rb @@ -1,3 +1,4 @@ +require "./lib/vocabularies/rdms" # Generated via # `rails generate hyrax:work Dataset` class Dataset < ActiveFedora::Base @@ -6,9 +7,73 @@ class Dataset < ActiveFedora::Base self.indexer = DatasetIndexer # Change this to restrict which works can be added as a child. # self.valid_child_concerns = [] - validates :title, presence: { message: 'Your work must have a title.' } + validates :title, presence: { message: 'Your dataset must have a title.' } + + # ------ properties from core metadata ------ + # property date_modified - not displayed (filled in by the system) + # property date_uploaded - not displayed (filled in by the system) + # property depositor - not displayed (filled in by the system) + # property title - keep + + # ------ properties from basic metadata ------ + # property alternative_title - keep + # property label - not displayed, used for file version label + # property relative_path - not displayed, used for file storage + # property import_url - not displayed, used for file imports + # property resource_type - keep + # property creator - do not display + # property contributor - do not display + # property description - keep + # property abstract - keep + # property keyword - keep + # property license - keep + # property rights_notes - do not display + # property rights_statement - do not display + # property access_right - do not display + # property publisher - keep + # property date_created - do not display + # property subject - keep + # property language - keep + # property identifier - do not display (used to store alternate identifiers) + # property based_near - do not display + # property related_url - do not display + # property bibliographic_citation - not displayed (generated by the system) + # property source - do not display (should be filled in by the system for bulk imports) + + property :doi, predicate: ::RDF::Vocab::DataCite.doi, multiple: false do |index| + index.as :symbol + end + + property :complex_person, predicate: ::RDF::Vocab::SIOC.has_creator, class_name:"ComplexPerson" + + # property :date_published, predicate: ::RDF::Vocab::Rdms.datePublished, multiple: false do |index| + # index.type :date + # index.as :stored_sortable + # end + + property :complex_date, predicate: ::RDF::Vocab::DC.date, class_name:"ComplexDate" + + property :complex_identifier, predicate: ::RDF::Vocab::Rdms.identifier, class_name:"ComplexIdentifier" + + # size and format to be obtained from the files attached + + # label property in basic metadata can be used for version label + + # description and abstract is in the basic metadata. Ignoring other descriptions for now. + + # Geolocation - would this be used? Ignoring for now. + + property :complex_funding_reference, predicate: ::RDF::Vocab::DataCite.fundref, class_name:"ComplexFundingReference" + + property :complex_relation, predicate: ::RDF::Vocab::DC.relation, class_name:"ComplexRelation" # 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_person, reject_if: :person_blank, allow_destroy: true + 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_funding_reference, reject_if: :fundref_blank, allow_destroy: true + accepts_nested_attributes_for :complex_relation, reject_if: :relation_blank, allow_destroy: true end diff --git a/hyrax/app/models/doi.rb b/hyrax/app/models/doi.rb new file mode 100644 index 0000000000000000000000000000000000000000..7d78764eff08151572872b029e9b970c631251b6 --- /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/handle.rb b/hyrax/app/models/handle.rb new file mode 100644 index 0000000000000000000000000000000000000000..a87518364bef3d56040825e7a584e9f58e2b82c7 --- /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/solr_document.rb b/hyrax/app/models/solr_document.rb index d8673266226df7c4d4977284f82bee8c5bbbfdd4..fac691a2044926c6eb2616c6982abfbbfb1792ce 100644 --- a/hyrax/app/models/solr_document.rb +++ b/hyrax/app/models/solr_document.rb @@ -25,4 +25,48 @@ class SolrDocument # Do content negotiation for AF models. use_extension( Hydra::ContentNegotiation ) + + def complex_date + self[Solrizer.solr_name('complex_date', :displayable)] + end + + def complex_identifier + self[Solrizer.solr_name('complex_identifier', :displayable)] + end + + def complex_person + self[Solrizer.solr_name('complex_person', :displayable)] + end + + def doi + self[Solrizer.solr_name('doi', :symbol)] + end + + def complex_relation + self[Solrizer.solr_name('complex_relation', :displayable)] + end + + def complex_funding_reference + self[Solrizer.solr_name('complex_funding_reference', :displayable)] + end + + def modality + self[Solrizer.solr_name('modality', :stored_searchable)] + end + + def complex_subject + self[Solrizer.solr_name('complex_subject', :displayable)] + end + + def approval_number + self[Solrizer.solr_name('approval_number', :symbol)] + end + + def extra_information + self[Solrizer.solr_name('extra_information', :stored_searchable)] + end + + def software_version + self[Solrizer.solr_name('software_version', :stored_searchable)] + end end diff --git a/hyrax/app/presenters/hyrax/crc_dataset_presenter.rb b/hyrax/app/presenters/hyrax/crc_dataset_presenter.rb new file mode 100644 index 0000000000000000000000000000000000000000..7f2895ced19067f58836dca28c774f010410ef7e --- /dev/null +++ b/hyrax/app/presenters/hyrax/crc_dataset_presenter.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +module Hyrax + class CrcDatasetPresenter < Hyrax::WorkShowPresenter + delegate :complex_date, :complex_identifier, :doi, :complex_person, :complex_funding_reference, + :complex_relation, :modality, :complex_subject, :approval_number, :extra_information, + :software_version, to: :solr_document + end +end diff --git a/hyrax/app/presenters/hyrax/dataset_presenter.rb b/hyrax/app/presenters/hyrax/dataset_presenter.rb index 5cca1d77f105a8130670d28bc654afb37fd2f3bb..8b127d9b7b5399fbdf696e2131efd449f58e5d29 100644 --- a/hyrax/app/presenters/hyrax/dataset_presenter.rb +++ b/hyrax/app/presenters/hyrax/dataset_presenter.rb @@ -2,5 +2,7 @@ # `rails generate hyrax:work Dataset` module Hyrax class DatasetPresenter < Hyrax::WorkShowPresenter + delegate :complex_date, :complex_identifier, :doi, :complex_person, + :complex_funding_reference, :complex_relation, to: :solr_document 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 0000000000000000000000000000000000000000..0fa7693d42266c39e0986ee29d8b81d937bb9b52 --- /dev/null +++ b/hyrax/app/renderers/nested_attribute_renderer.rb @@ -0,0 +1,109 @@ +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 << "<li#{html_attributes(attributes)}>#{inner_text}</li>" if inner_text.present? + end + + if !options[:include_empty] and inner_markup.present? + markup << %(<dt>#{label}</dt>\n<dd><ul class='tabular'>) + markup << inner_markup + markup << %(</ul></dd>) + end + sanitize(markup) + 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 += '<div class="row">' + row += "<div class=\"col-md-3\"><label>#{label}</label></div>" + if label =~ /^doi$/i || DOI.match_doi_prefix(val) + row += "<div class=\"col-md-9\">#{get_doi_hyperlink(val)}</div>" + elsif Handle.match_hdl_prefix(val) + row += "<div class=\"col-md-9\">#{get_handle_hyperlink(val)}</div>" + elsif label =~/^orcid|rights$/i + row += "<div class=\"col-md-9\">#{get_hyperlink(val)}</div>" + else + row += "<div class=\"col-md-9\">#{val}</div>" + end + row += "</div>" + row + end + + def get_label_row(label) + row = '' + row += '<div class="row label-row">' + row += "<div class=\"col-md-12\"><label>#{label}</label></div>" + row += "</div>" + 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_hyperlink(val) + Rinku.auto_link(val, :all, '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(field, 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 = '<div class="each_metadata">' + html_out += html + html_out += '</div>' + end + html_out + end + + def get_ouput_html(html) + html_out = '' + unless html.blank? + html_out = '<div class="metadata_property">' + html_out += html + html_out += '</div>' + end + 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 0000000000000000000000000000000000000000..7234315907a899f17533e488d249f08ba8906e97 --- /dev/null +++ b/hyrax/app/renderers/nested_date_attribute_renderer.rb @@ -0,0 +1,27 @@ +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_funding_reference_attribute_renderer.rb b/hyrax/app/renderers/nested_funding_reference_attribute_renderer.rb new file mode 100644 index 0000000000000000000000000000000000000000..36619570d17949eb596c3d02d5fa5f2de8d29ff7 --- /dev/null +++ b/hyrax/app/renderers/nested_funding_reference_attribute_renderer.rb @@ -0,0 +1,38 @@ +class NestedFundingReferenceAttributeRenderer < 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('funder_identifier').blank? + label = 'Funder identifier' + val = v['funder_identifier'][0] + each_html += get_row(label, val) + end + unless v.dig('funder_name').blank? + label = 'Funder name' + val = v['funder_name'][0] + each_html += get_row(label, val) + end + unless v.dig('award_number').blank? + label = 'Award number' + val = v['award_number'][0] + each_html += get_row(label, val) + end + unless v.dig('award_uri').blank? + label = 'Award URI' + val = v['award_uri'][0] + each_html += get_row(label, val) + end + unless v.dig('award_title').blank? + label = 'Award title' + val = v['award_title'][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 \ No newline at end of file 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 0000000000000000000000000000000000000000..3107036734db9302ee47288f77136cbd742615fe --- /dev/null +++ b/hyrax/app/renderers/nested_identifier_attribute_renderer.rb @@ -0,0 +1,24 @@ +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_person_attribute_renderer.rb b/hyrax/app/renderers/nested_person_attribute_renderer.rb new file mode 100644 index 0000000000000000000000000000000000000000..e64052c3bf5bd73da680712a12e9d7da23676821 --- /dev/null +++ b/hyrax/app/renderers/nested_person_attribute_renderer.rb @@ -0,0 +1,61 @@ +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 + + # role + unless v.dig('role').blank? + label = 'Role' + val = v['role'][0] + term = RoleService.new.find_by_id(val) + val = term['id'] if term.any? #using id as proxy for English-only text + each_html += get_row(label, val) + end + + # Workaround for nested properties + # orcid + unless v.dig('orcid').blank? + label = 'ORCID' + val = v['orcid'][0] + each_html += get_row(label, val) + end + + # affiliation + unless v.dig('affiliation').blank? + label = 'Affiliation' + val = v['affiliation'][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 0000000000000000000000000000000000000000..8554cf43d07f5f8c279b54ea923b778bf6161507 --- /dev/null +++ b/hyrax/app/renderers/nested_relation_attribute_renderer.rb @@ -0,0 +1,41 @@ +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 = "<span class='glyphicon glyphicon-new-window'></span> #{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_subject_attribute_renderer.rb b/hyrax/app/renderers/nested_subject_attribute_renderer.rb new file mode 100644 index 0000000000000000000000000000000000000000..262e3d7dbea71d0030a2b45b845f2859833bf276 --- /dev/null +++ b/hyrax/app/renderers/nested_subject_attribute_renderer.rb @@ -0,0 +1,43 @@ +class NestedSubjectAttributeRenderer < 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 = '' + # Identifier + unless v.dig('subject_identifier').blank? + label = t('rdms.fields.complex_subject_identifier') + val = v['subject_identifier'][0] + each_html += get_row(label, val) + end + # Species + unless v.dig('subject_species').blank? + label = t('rdms.fields.complex_subject_species') + val = v['subject_species'][0] + each_html += get_row(label, val) + end + # type + unless v.dig('subject_type').blank? + label = t('rdms.fields.complex_subject_type') + val = v['subject_type'][0] + each_html += get_row(label, val) + end + # sex + unless v.dig('subject_sex').blank? + label = t('rdms.fields.complex_subject_sex') + val = v['subject_sex'][0] + each_html += get_row(label, val) + end + # age + unless v.dig('subject_age').blank? + label = t('rdms.fields.complex_subject_age') + val = v['subject_age'][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/services/crc_resource_type_service.rb b/hyrax/app/services/crc_resource_type_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..3a68cb367af34f6d966ea15972484bc9ceafb7e2 --- /dev/null +++ b/hyrax/app/services/crc_resource_type_service.rb @@ -0,0 +1,6 @@ +# Provide select options for CRC Resource types +class CrcResourceTypeService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('crc_resource_types') + end +end diff --git a/hyrax/app/services/date_service.rb b/hyrax/app/services/date_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..415253a3d496034f27a00f116b56101bde46d91d --- /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/identifier_service.rb b/hyrax/app/services/identifier_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..2c813d44d1e6fed39fc70109267705f59e353abe --- /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/license_service.rb b/hyrax/app/services/license_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..cd53bf4b130865f237e36ba3fc4d3840f3b945d9 --- /dev/null +++ b/hyrax/app/services/license_service.rb @@ -0,0 +1,6 @@ +# Provide select options for analysis fields +class LicenseService < QaSelectServiceExtended + def initialize(_authority_name = nil) + super('licenses') + 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 0000000000000000000000000000000000000000..ee9e47b1b177590ad5289ce09937bfcbcca3c11c --- /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 0000000000000000000000000000000000000000..32b3876c1ceba1fc7da85e1df32797a3d1495a92 --- /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_statement_service.rb b/hyrax/app/services/rights_statement_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..a601c760e1d30c31ff5368f4489f91b4e4e5ae06 --- /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 0000000000000000000000000000000000000000..d9994a903498acb8a507e7f41b0923201031f3bd --- /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/views/hyrax/crc_datasets/_attribute_rows.html.erb b/hyrax/app/views/hyrax/crc_datasets/_attribute_rows.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..4e8be8e0305416daf7ffe53cba48145838073557 --- /dev/null +++ b/hyrax/app/views/hyrax/crc_datasets/_attribute_rows.html.erb @@ -0,0 +1,41 @@ +<!-- Accordion wrapper --> +<div class="panel-group" id="accordion"> + + <!-- Description accordion --> + <div class="panel panel-default"> + <!-- Accordion header --> + <div class="panel-heading" data-toggle="collapse" data-target="#description"> + <h4 class="panel-title"> + <a class="accordion-toggle">Description</a> + </h4> + </div> <!-- Accordion header --> + <!-- Accordion body --> + <div id="description" class="panel-collapse collapse in"> + <div class="panel-body"> + <%= presenter.attribute_to_html(:doi, label: t('rdms.fields.doi'), html_dl: true) %> + <%= presenter.attribute_to_html(:title, label: t('rdms.fields.title'), html_dl: true) %> + <%= presenter.attribute_to_html(:alternative_title, label: t('rdms.fields.alternative_title'), html_dl: true) %> + <%= presenter.attribute_to_html(:complex_person, render_as: :nested_person, label: t('rdms.fields.complex_person'), html_dl: true) %> + <%= presenter.attribute_to_html(:resource_type, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:abstract, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:description, render_as: :faceted, 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(:complex_date, render_as: :nested_date, label: t('rdms.fields.complex_date'), html_dl: true) %> + <%= presenter.attribute_to_html(:complex_identifier, render_as: :nested_identifier, label: t('rdms.fields.complex_identifier'), html_dl: true) %> + <%= presenter.attribute_to_html(:modality, label: t('rdms.fields.modality'), html_dl: true) %> + <%= presenter.attribute_to_html(:complex_subject, render_as: :nested_subject, label: t('rdms.fields.complex_subject'), html_dl: true) %> + <%= presenter.attribute_to_html(:approval_number, label: t('rdms.fields.approval_number'), html_dl: true) %> + <%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:publisher, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:language, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:complex_funding_reference, render_as: :nested_funding_reference, label: t('rdms.fields.complex_funding_reference'), html_dl: true) %> + <%= presenter.attribute_to_html(:complex_relation, render_as: :nested_relation, label: t('rdms.fields.complex_relation'), html_dl: true) %> + <%= presenter.attribute_to_html(:software_version, label: t('rdms.fields.software_version'), html_dl: true) %> + <%= presenter.attribute_to_html(:extra_information, label: t('rdms.fields.extra_information'), html_dl: true) %> + </div> <!-- panel body --> + </div> <!-- Accordion body --> + </div> <!-- Description accordion --> +</div> +<!-- Accordion wrapper --> diff --git a/hyrax/app/views/hyrax/crc_datasets/_crc_dataset.html.erb b/hyrax/app/views/hyrax/crc_datasets/_crc_dataset.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..ddce373d3229a77cfa9f0e99ef0a4f7f358e77b3 --- /dev/null +++ b/hyrax/app/views/hyrax/crc_datasets/_crc_dataset.html.erb @@ -0,0 +1,2 @@ +<%# This is a search result view %> +<%= render 'catalog/document', document: crc_dataset, document_counter: crc_dataset_counter %> 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 0000000000000000000000000000000000000000..f591b6dcf431b74d7557109e9e20687a132d1f20 --- /dev/null +++ b/hyrax/app/views/hyrax/datasets/_attribute_rows.html.erb @@ -0,0 +1,36 @@ +<!-- Accordion wrapper --> +<div class="panel-group" id="accordion"> + + <!-- Description accordion --> + <div class="panel panel-default"> + <!-- Accordion header --> + <div class="panel-heading" data-toggle="collapse" data-target="#description"> + <h4 class="panel-title"> + <a class="accordion-toggle">Description</a> + </h4> + </div> <!-- Accordion header --> + <!-- Accordion body --> + <div id="description" class="panel-collapse collapse in"> + <div class="panel-body"> + <%= presenter.attribute_to_html(:doi, label: 'DOI', html_dl: true) %> + <%= presenter.attribute_to_html(:title, label: t('Title'), html_dl: true) %> + <%= presenter.attribute_to_html(:alternative_title, label: t('rdms.fields.alternative_title'), html_dl: true) %> + <%= presenter.attribute_to_html(:complex_person, render_as: :nested_person, label: t('rdms.fields.complex_person'), html_dl: true) %> + <%= presenter.attribute_to_html(:resource_type, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:abstract, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:description, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:publisher, render_as: :faceted, html_dl: true) %> + <%= presenter.attribute_to_html(:language, render_as: :faceted, 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(:complex_date, render_as: :nested_date, label: t('rdms.fields.complex_date'), html_dl: true) %> + <%= presenter.attribute_to_html(:complex_identifier, render_as: :nested_identifier, label: t('rdms.fields.complex_identifier'), html_dl: true) %> + <%= presenter.attribute_to_html(:complex_funding_reference, render_as: :nested_funding_reference, label: t('rdms.fields.complex_funding_reference'), html_dl: true) %> + <%= presenter.attribute_to_html(:complex_relation, render_as: :nested_relation, label: t('rdms.fields.complex_relation'), html_dl: true) %> + </div> <!-- panel body --> + </div> <!-- Accordion body --> + </div> <!-- Description accordion --> +</div> +<!-- Accordion wrapper --> 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 0000000000000000000000000000000000000000..727c3462aad35322ecb8e018238685057d662250 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_date.html.erb @@ -0,0 +1,15 @@ +<div class="multi-nested multi_value custom_field"> + <%= f.input :complex_date, + as: :nested_date, + include_blank: false, + input_html: { + class: '', + data: {name: :complex_date} + }, + required: f.object.required?(:complex_date) + %> + <button type="button" class="btn btn-link add"> + <span class="glyphicon glyphicon-plus"></span> + <span class="controls-add-text">Add another date</span> + </button> +</div> diff --git a/hyrax/app/views/records/edit_fields/_complex_funding_reference.html.erb b/hyrax/app/views/records/edit_fields/_complex_funding_reference.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..70e0ec9bfa6478f982d094b1c5ba46d0170fec6f --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_funding_reference.html.erb @@ -0,0 +1,15 @@ +<div class="multi-nested"> + <%= f.input :complex_funding_reference, + as: :nested_funding_reference, + include_blank: false, + input_html: { + class: '', + data: {name: :complex_funding_reference} + }, + required: f.object.required?(:complex_funding_reference) + %> + <button type="button" class="btn btn-link add"> + <span class="glyphicon glyphicon-plus"></span> + <span class="controls-add-text">Add another funding reference</span> + </button> +</div> 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 0000000000000000000000000000000000000000..10d01bb25c8bf1106f83f7728f3add7a006a6e91 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_identifier.html.erb @@ -0,0 +1,15 @@ +<div class="multi-nested multi_value custom_field"> + <%= f.input :complex_identifier, + as: :nested_identifier, + include_blank: false, + input_html: { + class: '', + data: {name: :complex_identifier} + }, + required: f.object.required?(:complex_identifier) + %> + <button type="button" class="btn btn-link add"> + <span class="glyphicon glyphicon-plus"></span> + <span class="controls-add-text">Add another identifier</span> + </button> +</div> 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 0000000000000000000000000000000000000000..f33ada4ffe7a3099456b3ab9ba63907c91b6bd53 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_person.html.erb @@ -0,0 +1,15 @@ +<div class="multi-nested multi_value custom_field"> + <%= f.input :complex_person, + as: :nested_person, + include_blank: false, + input_html: { + class: '', + data: {name: :complex_person} + }, + required: f.object.required?(:complex_person) + %> + <button type="button" class="btn btn-link add"> + <span class="glyphicon glyphicon-plus"></span> + <span class="controls-add-text">Add another person</span> + </button> +</div> 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 0000000000000000000000000000000000000000..d6b0648c6c7c6f7277d81b07c14e837986ddf578 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_relation.html.erb @@ -0,0 +1,15 @@ +<div class="multi-nested"> + <%= f.input :complex_relation, + as: :nested_relation, + include_blank: false, + input_html: { + class: '', + data: {name: :complex_relation} + }, + required: f.object.required?(:complex_relation) + %> + <button type="button" class="btn btn-link add"> + <span class="glyphicon glyphicon-plus"></span> + <span class="controls-add-text">Add another relationship</span> + </button> +</div> diff --git a/hyrax/app/views/records/edit_fields/_complex_subject.html.erb b/hyrax/app/views/records/edit_fields/_complex_subject.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..7f385432e595b0d4426b26a27335b86442f7ffb7 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_complex_subject.html.erb @@ -0,0 +1,15 @@ +<div class="multi-nested multi_value custom_field"> + <%= f.input :complex_subject, + as: :nested_subject, + include_blank: false, + input_html: { + class: '', + data: {name: :complex_subject} + }, + required: f.object.required?(:complex_subject) + %> + <button type="button" class="btn btn-link add"> + <span class="glyphicon glyphicon-plus"></span> + <span class="controls-add-text">Add another subject</span> + </button> +</div> diff --git a/hyrax/app/views/records/edit_fields/_crc_resource_type.html.erb b/hyrax/app/views/records/edit_fields/_crc_resource_type.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..40848b2ab82f71a3acd1dd8780e4c2e441fb0e94 --- /dev/null +++ b/hyrax/app/views/records/edit_fields/_crc_resource_type.html.erb @@ -0,0 +1,7 @@ +<% service = CrcResourceTypeService.new %> +<%= f.input :crc_resource_type, as: :select, + collection: service.select_all_options, + include_blank: true, + item_helper: service.method(:include_current_value), + input_html: { class: 'form-control' } +%> diff --git a/hyrax/config/application.rb b/hyrax/config/application.rb index 4d48786828e8ced9c4223d81f9fbf840e56c42e6..a3cf5499a6b3adfc04f2c38d340187b289ac7e9b 100644 --- a/hyrax/config/application.rb +++ b/hyrax/config/application.rb @@ -15,5 +15,17 @@ module Hyrax3App # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. + + 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.i18n.default_locale = :en + config.i18n.available_locales = [:en, :de] + config.i18n.fallbacks = [:en] + + config.action_dispatch.default_headers['Referrer-Policy'] = 'strict-origin-when-cross-origin' end end diff --git a/hyrax/config/authorities/crc_resource_types.yml b/hyrax/config/authorities/crc_resource_types.yml new file mode 100644 index 0000000000000000000000000000000000000000..202e45f1b32ae62b182045ae5ddb1c44a93a97e0 --- /dev/null +++ b/hyrax/config/authorities/crc_resource_types.yml @@ -0,0 +1,7 @@ +terms: + - id: Analysed + term: Analysed + - id: Measured + term: Measured + - id: Simulated + term: Simulated diff --git a/hyrax/config/authorities/dates.yml b/hyrax/config/authorities/dates.yml new file mode 100644 index 0000000000000000000000000000000000000000..61038691d668dcd70b1669a80509f94f342f3645 --- /dev/null +++ b/hyrax/config/authorities/dates.yml @@ -0,0 +1,31 @@ +terms: + - id: http://purl.org/dc/terms/dateAccepted + term: Accepted + active: true + - id: Available + term: Available (Embargo release) + 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: record date + term: Record date + active: true + - id: Registered + term: Registered + active: true + - id: http://bibframe.org/vocab/providerDate + term: Submitted + active: true + - id: http://bibframe.org/vocab/changeDate + term: Updated + active: true diff --git a/hyrax/config/authorities/identifiers.yml b/hyrax/config/authorities/identifiers.yml new file mode 100644 index 0000000000000000000000000000000000000000..9d9ccbd0b978a73ba4c4b3c8aca40ffa2401a884 --- /dev/null +++ b/hyrax/config/authorities/identifiers.yml @@ -0,0 +1,43 @@ +terms: + - id: group id + term: Group id + active: true + - 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: 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: other + term: Other + active: true diff --git a/hyrax/config/authorities/licenses.yml b/hyrax/config/authorities/licenses.yml index 89dd602ade439e648242728c2a5aef31ad821801..653aff475bd9e071f6aa91c14d0e74b1ead69f2e 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/relationships.yml b/hyrax/config/authorities/relationships.yml new file mode 100644 index 0000000000000000000000000000000000000000..601ce6d33dab7c1e37c09a31266cbe04298ea58a --- /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 69c22256a6287501d9b005fa94fd48c7c7ee3b3c..5eeb04c5ef0c177015fa6c50740ce11f6c68a437 100644 --- a/hyrax/config/authorities/resource_types.yml +++ b/hyrax/config/authorities/resource_types.yml @@ -5,8 +5,6 @@ terms: term: Audio - id: Book term: Book - - id: Capstone Project - term: Capstone Project - id: Conference Proceeding term: Conference Proceeding - id: Dataset @@ -17,22 +15,14 @@ terms: 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/rights_statements.yml b/hyrax/config/authorities/rights_statements.yml index 719e7576afebfdc69fd54dfeeec47c50ffcc4672..653aff475bd9e071f6aa91c14d0e74b1ead69f2e 100644 --- a/hyrax/config/authorities/rights_statements.yml +++ b/hyrax/config/authorities/rights_statements.yml @@ -1,37 +1,37 @@ terms: -- id: http://rightsstatements.org/vocab/InC/1.0/ - term: "In Copyright" - active: true -- id: http://rightsstatements.org/vocab/InC-OW-EU/1.0/ - term: "In Copyright - EU Orphan Work" - active: true -- id: http://rightsstatements.org/vocab/InC-EDU/1.0/ - term: "In Copyright - Educational Use Permitted" - active: true -- id: http://rightsstatements.org/vocab/InC-NC/1.0/ - term: "In Copyright - Non-Commercial Use Permitted" - active: true -- id: http://rightsstatements.org/vocab/InC-RUU/1.0/ - term: "In Copyright - Rights-holder(s) Unlocatable or Unidentifiable" - active: true -- id: http://rightsstatements.org/vocab/NoC-CR/1.0/ - term: "No Copyright - Contractual Restrictions" - active: true -- id: http://rightsstatements.org/vocab/NoC-NC/1.0/ - term: "No Copyright - Non-Commercial Use Only " - active: true -- id: http://rightsstatements.org/vocab/NoC-OKLR/1.0/ - term: "No Copyright - Other Known Legal Restrictions" - active: true -- id: http://rightsstatements.org/vocab/NoC-US/1.0/ - term: "No Copyright - United States" - active: true -- id: http://rightsstatements.org/vocab/CNE/1.0/ - term: "Copyright Not Evaluated" - active: true -- id: http://rightsstatements.org/vocab/UND/1.0/ - term: "Copyright Undetermined" - active: true -- id: http://rightsstatements.org/vocab/NKC/1.0/ - term: "No Known Copyright" - active: true + - 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 + - id: https://creativecommons.org/licenses/by-sa/4.0/ + term: Creative Commons BY-SA Attribution-ShareAlike 4.0 International + active: true + - id: https://creativecommons.org/licenses/by-nd/4.0/ + term: Creative Commons BY-ND Attribution-NoDerivatives 4.0 International + active: true + - id: https://creativecommons.org/licenses/by-nc/4.0/ + term: Creative Commons BY-NC Attribution-NonCommercial 4.0 International + active: true + - id: https://creativecommons.org/licenses/by-nc-nd/4.0/ + term: Creative Commons BY-NC-ND Attribution-NonCommercial-NoDerivs 4.0 International + active: true + - id: https://creativecommons.org/licenses/by-nc-sa/4.0/ + term: Creative Commons BY-NC-SA Attribution-NonCommercial-ShareAlike 4.0 International + active: true + - id: http://creativecommons.org/publicdomain/zero/1.0/ + term: Creative Commons CC0 1.0 Universal + active: true + - 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/roles.yml b/hyrax/config/authorities/roles.yml new file mode 100644 index 0000000000000000000000000000000000000000..93e508a38308f9de9178bd3dbcb211667c24c59d --- /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: non-author contact + active: true + - id: operator + term: operator + active: true diff --git a/hyrax/config/environments/development.rb b/hyrax/config/environments/development.rb index 298ac03b7407c42ae47be21d961be4b1a0b639ea..3fe58d504e1b05a5505c4f1a0b0e4bfd9e036407 100644 --- a/hyrax/config/environments/development.rb +++ b/hyrax/config/environments/development.rb @@ -30,6 +30,9 @@ Rails.application.configure do # Store uploaded files on the local file system (see config/storage.yml for options) config.active_storage.service = :local + # 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 @@ -55,9 +58,12 @@ Rails.application.configure do # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + Rails.application.routes.default_url_options = { host: ENV.fetch('APP_HOST') { 'localhost' } } + # 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 + config.web_console.whitelisted_ips = ["172.0.0.0/8", '192.168.0.0/16', '127.0.0.1'] config.force_ssl = false if ENV['APP_HOST'].present? diff --git a/hyrax/config/environments/production.rb b/hyrax/config/environments/production.rb index 52dfc44d78208f962ddf371af5722811ef6b2c08..cf85b5457a0c4491960f476e2aad61aaa4af4f10 100644 --- a/hyrax/config/environments/production.rb +++ b/hyrax/config/environments/production.rb @@ -17,6 +17,9 @@ Rails.application.configure do config.consider_all_requests_local = false config.action_controller.perform_caching = true + # Use Sidekiq to process background jobs + config.active_job.queue_adapter = :sidekiq + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). # config.require_master_key = true @@ -54,15 +57,41 @@ Rails.application.configure do # 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 + Rails.application.routes.default_url_options = \ + Hyrax::Engine.routes.default_url_options = \ + {protocol: 'http', host: ENV['APP_HOST']} + config.application_url = "http://#{ENV['APP_HOST']}" + else + config.force_ssl = true #default if nothing specified is more secure. + Rails.application.routes.default_url_options = \ + Hyrax::Engine.routes.default_url_options = \ + {protocol: 'https', host: ENV['APP_HOST']} + config.application_url = "https://#{ENV['APP_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 = :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 @@ -83,33 +112,15 @@ Rails.application.configure do # 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 - if ENV["RAILS_FORCE_SSL"].present? && (ENV["RAILS_FORCE_SSL"].to_s.downcase == 'false') then - config.force_ssl = false - Rails.application.routes.default_url_options = \ - Hyrax::Engine.routes.default_url_options = \ - {protocol: 'http', host: ENV['APP_HOST']} - config.application_url = "http://#{ENV['APP_HOST']}" - else - config.force_ssl = true #default if nothing specified is more secure. - Rails.application.routes.default_url_options = \ - Hyrax::Engine.routes.default_url_options = \ - {protocol: 'https', host: ENV['APP_HOST']} - config.application_url = "https://#{ENV['APP_HOST']}" - end + 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 77553f7e7faff573cfe37d6d1fa3bac331025bb9..6546a62d81bbc63a65257000aecf9831bd6351cb 100644 --- a/hyrax/config/environments/test.rb +++ b/hyrax/config/environments/test.rb @@ -15,7 +15,7 @@ Rails.application.configure do # 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=#{1.hour.to_i}" + 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}" } # Show full error reports and disable caching. @@ -44,6 +44,9 @@ Rails.application.configure do # 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 + if ENV['APP_HOST'].present? Rails.application.routes.default_url_options = {protocol: 'http', host: ENV['APP_HOST']} Hyrax::Engine.routes.default_url_options = {protocol: 'http', host: ENV['APP_HOST']} diff --git a/hyrax/config/initializers/clamav.rb b/hyrax/config/initializers/clamav.rb index 7dcb60d7e3425d53447fc1a3babc650bd8ba3a12..7cd26d6a28befc8f9639aa7adc17df41afdcc07e 100644 --- a/hyrax/config/initializers/clamav.rb +++ b/hyrax/config/initializers/clamav.rb @@ -1,2 +1 @@ -# frozen_string_literal: true ClamAV.instance.loaddb if defined? ClamAV diff --git a/hyrax/config/initializers/hyrax.rb b/hyrax/config/initializers/hyrax.rb index f470e5472516290cd4fdfb29cc6cc870ffd079dd..70ad02ac8dbf57dd8f1a541c0f882baeb69d7d27 100644 --- a/hyrax/config/initializers/hyrax.rb +++ b/hyrax/config/initializers/hyrax.rb @@ -2,6 +2,8 @@ Hyrax.config do |config| # Injected via `rails g hyrax:work Dataset` config.register_curation_concern :dataset + # Injected via `rails g hyrax:work CrcDataset` + config.register_curation_concern :crc_dataset # 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 @@ -60,14 +62,18 @@ Hyrax.config do |config| # 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 = "tzrb-.zddddd" - # 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" diff --git a/hyrax/config/initializers/redis_config.rb b/hyrax/config/initializers/redis_config.rb index 313cf19c3d9cdb2ff364b34c0893a38623fa5088..aad03ef3bd37c82ffe4d2eac4eca36dcfe779324 100644 --- a/hyrax/config/initializers/redis_config.rb +++ b/hyrax/config/initializers/redis_config.rb @@ -1,4 +1,3 @@ -# frozen_string_literal: true require 'redis' config = YAML.safe_load(ERB.new(IO.read(Rails.root.join('config', 'redis.yml'))).result)[Rails.env].with_indifferent_access Redis.current = Redis.new(config.merge(thread_safe: true)) diff --git a/hyrax/config/initializers/riiif.rb b/hyrax/config/initializers/riiif.rb index b29200cc14e01296b83444d626df80d3914f6266..76e7e59bf93779a8317a5920a32ec4c59f0d8b11 100644 --- a/hyrax/config/initializers/riiif.rb +++ b/hyrax/config/initializers/riiif.rb @@ -1,4 +1,3 @@ -# frozen_string_literal: true ActiveSupport::Reloader.to_prepare do Riiif::Image.file_resolver = Riiif::HttpFileResolver.new Riiif::Image.info_service = lambda do |id, _file| diff --git a/hyrax/config/initializers/sidekiq.rb b/hyrax/config/initializers/sidekiq.rb new file mode 100644 index 0000000000000000000000000000000000000000..351838d72a28f03922915e37236944b360b45fdf --- /dev/null +++ b/hyrax/config/initializers/sidekiq.rb @@ -0,0 +1,17 @@ +# 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' + +redis_conn = { url: "redis://#{config[:host]}:#{config[:port]}/" } + +Sidekiq.configure_server do |s| + # s.redis = redis_conn + s.redis = redis_config +end + +Sidekiq.configure_client do |s| + # s.redis = redis_conn + s.redis = redis_config +end diff --git a/hyrax/config/initializers/simple_form.rb b/hyrax/config/initializers/simple_form.rb index b92657cf48025dcb9d8db06241ea0abad4fb8952..a561d3acb2fd9f7a37004dd60345ffb061eb773e 100644 --- a/hyrax/config/initializers/simple_form.rb +++ b/hyrax/config/initializers/simple_form.rb @@ -1,4 +1,3 @@ -# frozen_string_literal: true # NOTE: This is a modified version of simple_form's default config file. # The only changes were to move the input to after the hint and error. diff --git a/hyrax/config/initializers/simple_form_bootstrap.rb b/hyrax/config/initializers/simple_form_bootstrap.rb index 094cb3bcd70c681b1b69dab194654aa674c21866..c5ee0408dbde5d739095396aa771c8085b99f73a 100644 --- a/hyrax/config/initializers/simple_form_bootstrap.rb +++ b/hyrax/config/initializers/simple_form_bootstrap.rb @@ -1,4 +1,3 @@ -# frozen_string_literal: true # NOTE: This is a modified version of simple_form's default config file. # The only changes were to move the inputs to after the hints and errors. diff --git a/hyrax/config/initializers/work_form_override.rb b/hyrax/config/initializers/work_form_override.rb new file mode 100644 index 0000000000000000000000000000000000000000..174cb570b028cf32c9f9185403692de4a3271275 --- /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/locales/crc_dataset.de.yml b/hyrax/config/locales/crc_dataset.de.yml new file mode 100644 index 0000000000000000000000000000000000000000..cce037314ebeb66a9b5d9084a9c3683cd61f2a48 --- /dev/null +++ b/hyrax/config/locales/crc_dataset.de.yml @@ -0,0 +1,8 @@ +de: + hyrax: + icons: + crc_dataset: 'fa fa-file-text-o' + select_type: + crc_dataset: + description: "Crc dataset Werke" + name: "Crc Dataset" diff --git a/hyrax/config/locales/crc_dataset.en.yml b/hyrax/config/locales/crc_dataset.en.yml new file mode 100644 index 0000000000000000000000000000000000000000..23309b6904902ccaf47da688fea3179d83a745c2 --- /dev/null +++ b/hyrax/config/locales/crc_dataset.en.yml @@ -0,0 +1,21 @@ +en: + hyrax: + icons: + crc_dataset: 'fa fa-file-text-o' + select_type: + crc_dataset: + description: "CRC dataset works" + name: "CRC Dataset" + simple_form: + labels: + dataset: + complex_date: "Date" + complex_funding_reference: "Funding reference" + complex_identifier: "Identifiers" + complex_person: "Creators and Contributors" + complex_relation: "Related items" + complex_subject: "Subject" + approval_number: "Animal/Ethics Approval No." + extra_information: "Extra information" + modality: "Modality" + software_version: "Software version" diff --git a/hyrax/config/locales/crc_dataset.es.yml b/hyrax/config/locales/crc_dataset.es.yml new file mode 100644 index 0000000000000000000000000000000000000000..fd578d048872176a13d7c1a54960d255cb747d3a --- /dev/null +++ b/hyrax/config/locales/crc_dataset.es.yml @@ -0,0 +1,10 @@ +es: + hyrax: + icons: + crc_dataset: 'fa fa-file-text-o' + select_type: + crc_dataset: + # TODO: translate `human_name` into Spanish + description: "Crc dataset trabajos" + name: "Crc Dataset" + # TODO: translate `human_name` into Spanish diff --git a/hyrax/config/locales/crc_dataset.fr.yml b/hyrax/config/locales/crc_dataset.fr.yml new file mode 100644 index 0000000000000000000000000000000000000000..7cb6311ab8b1af8c7373cc14de7be3d4236b6e77 --- /dev/null +++ b/hyrax/config/locales/crc_dataset.fr.yml @@ -0,0 +1,8 @@ +fr: + hyrax: + icons: + crc_dataset: 'fa fa-file-text-o' + select_type: + crc_dataset: + description: "Crc dataset Å“uvres" + name: "Crc Dataset" diff --git a/hyrax/config/locales/crc_dataset.it.yml b/hyrax/config/locales/crc_dataset.it.yml new file mode 100644 index 0000000000000000000000000000000000000000..de9cf83f2e471946ad58c21c30e7da4ca8a369cc --- /dev/null +++ b/hyrax/config/locales/crc_dataset.it.yml @@ -0,0 +1,8 @@ +it: + hyrax: + icons: + crc_dataset: 'fa fa-file-text-o' + select_type: + crc_dataset: + description: "Crc dataset opere" + name: "Crc Dataset" diff --git a/hyrax/config/locales/crc_dataset.pt-BR.yml b/hyrax/config/locales/crc_dataset.pt-BR.yml new file mode 100644 index 0000000000000000000000000000000000000000..35e3d451fe4964329e5bee74ea5c786f14246b78 --- /dev/null +++ b/hyrax/config/locales/crc_dataset.pt-BR.yml @@ -0,0 +1,8 @@ +pt-BR: + hyrax: + icons: + crc_dataset: 'fa fa-file-text-o' + select_type: + crc_dataset: + description: "Crc dataset obras" + name: "Crc Dataset" diff --git a/hyrax/config/locales/crc_dataset.zh.yml b/hyrax/config/locales/crc_dataset.zh.yml new file mode 100644 index 0000000000000000000000000000000000000000..30a9be85fd43db0e6be4749abddf1ee3a61d7577 --- /dev/null +++ b/hyrax/config/locales/crc_dataset.zh.yml @@ -0,0 +1,10 @@ +zh: + hyrax: + icons: + crc_dataset: 'fa fa-file-text-o' + select_type: + crc_dataset: + # TODO: translate `human_name` into Chinese + description: "Crc dataset 作å“" + name: "Crc Dataset" + # TODO: translate `human_name` into Chinese diff --git a/hyrax/config/locales/dataset.en.yml b/hyrax/config/locales/dataset.en.yml index dc79608c678531dbff3b83948229cb8aa24efb1c..60dd81276355c3f40a98a2b751b2985c60a78090 100644 --- a/hyrax/config/locales/dataset.en.yml +++ b/hyrax/config/locales/dataset.en.yml @@ -6,3 +6,12 @@ en: dataset: description: "Dataset works" name: "Dataset" + simple_form: + labels: + dataset: + complex_date: "Date" + complex_funding_reference: "Funding reference" + complex_identifier: "Identifiers" + complex_person: "Creators and Contributors" + complex_relation: "Related items" + complex_subject: "Subject" diff --git a/hyrax/config/locales/en.yml b/hyrax/config/locales/en.yml index decc5a85735df127f96b89043ed6c6911713941a..ae4051ff4f4da708db2839dec58ec720fa73059f 100644 --- a/hyrax/config/locales/en.yml +++ b/hyrax/config/locales/en.yml @@ -30,4 +30,41 @@ # available at http://guides.rubyonrails.org/i18n.html. en: - hello: "Hello world" + rdms: + fields: + alternative_title: "Alternative title" + approval_number: "Animal/Ethics Approval No." + complex_date: "Date" + complex_funding_reference: "Funding reference" + complex_identifier: "Identifier" + complex_person: "Creator or Contributor" + complex_relation: "Related item" + complex_subject: "Medical Subject" + complex_subject_identifier: "Subject identifier" + complex_subject_species: "Subject species" + complex_subject_type: "Subject type" + complex_subject_sex: "Subject sex" + complex_subject_age: "Subject age" + doi: "DOI" + extra_information: "Extra information" + first_name: "Given name" + full_name: "Full name" + last_name: "Surname" + modality: "Modality" + software_version: "Software version" + title: "Title" + simple_form: + hints: + defaults: + title: The title of your work. + abstract: Abstract or a free-text description for the work. + alternative_title: Alternative title or the title in another language, if applicable. + keyword: '<strong>Note:</strong> To enter multiple keywords, click on "Add another Keyword." Do not list them in a single field.' + license: License for your work. + resource_type: Type of content. More than one type may be selected. + publisher: The person or group making the work available. + complex_person: 'Authors or contributors to the work. Enter the Surname, the Given name, and the full name again in "Name", and select their Role.' + complex_identifier: External identifiers, if applicable. + placeholders: + defaults: + language: "De" diff --git a/hyrax/config/locales/hyrax.en.yml b/hyrax/config/locales/hyrax.en.yml index 15fc22f4168dd28a4aa6b310b34541a2986d435b..111713e54b67fdd830bd0a147369bca52ea1275e 100644 --- a/hyrax/config/locales/hyrax.en.yml +++ b/hyrax/config/locales/hyrax.en.yml @@ -12,7 +12,63 @@ en: language_sim: Language publisher_sim: Publisher subject_sim: Subject + # complex date + 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 funder + funder_sim: Funder + # complex identifier + complex_identifier_ssm: Identifier + complex_identifier_group_id_ssim: Group id + complex_identifier_project_id_ssim: Project id + # complex person + complex_person_sim: Creator + 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_contact_person_sim: Contact person + complex_person_corresponding_author_sim: Corresponding author + complex_person_operator_sim: Operator + complex_person_affiliation_sim: Affiliation + # complex relation + complex_relation_relationship_sim: Relationship + # complex subject + complex_subject_species_sim: Subject species + complex_subject_type_sim: Subject type + complex_subject_sex_sim: Subject sex + complex_subject_age_sim: Subject age + # modality + modality_sim: Modality index: + approval_number_ssm: Animal/Ethics Approval No. based_near_tesim: Location contributor_tesim: Contributor creator_tesim: Creator @@ -20,15 +76,64 @@ en: date_modified_dtsi: Date Modified date_uploaded_dtsi: Date Uploaded description_tesim: Description + extra_information_tesim: Extra information file_format_tesim: File Format identifier_tesim: Identifier keyword_tesim: Keyword language_tesim: Language license_tesim: License + modality_tesim: Modality publisher_tesim: Publisher rights_statement_tesim: Rights Statement + software_version_tesim: Software version subject_tesim: Subject + # complex date + 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 funder + award_title_tesim: Award title + award_number_ssim: Award number + funder_tesim: Funder + funder_identifier_ssim: Funder identifier + # complex identifier + complex_identifier_ssim: Identifier + complex_identifier_orcid_ssim: ORCID + complex_identifier_local_id_ssim: Local identifier + complex_identifier_group_id_ssim: Group id + complex_identifier_project_id_ssim: Project id + # complex person + complex_person_other_tesim: Creator + complex_person_author_tesim: Author + complex_person_editor_tesim: Editor + complex_person_translator_tesim: Translator + complex_person_data_depositor_tesim: Data depositor + complex_person_data_curator_tesim: Data curator + complex_person_operator_tesim: Operator + complex_person_contact_person_tesim: Contact person + complex_person_organization_tesim: Organization + complex_person_sub_organization_tesim: Sub organization + # complex relation + complex_relation_title_tesim: Title of related item + # complex subject + complex_subject_identifier_ssim: Subject identifier + complex_subject_species_tesim: Subject species + complex_subject_type_tesim: Subject type + complex_subject_sex_tesim: Subject sex + complex_subject_age_tesim: Subject age show: + approval_number_ssm: Animal/Ethics Approval No. based_near_tesim: Location contributor_tesim: Contributor creator_tesim: Creator @@ -36,15 +141,53 @@ en: date_modified_dtsi: Date Modified date_uploaded_dtsi: Date Uploaded description_tesim: Description + extra_information_tesim: Extra information file_format_tesim: File Format identifier_tesim: Identifier keyword_tesim: Keyword language_tesim: Language license_tesim: License + modality_tesim: Modality publisher_tesim: Publisher rights_statement_tesim: Rights Statement + software_version_tesim: Software version subject_tesim: Subject title_tesim: Title + # complex date + 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 funding + complex_funding_reference_ssm: Funding reference + # complex identifier + complex_identifier_ssm: Identifier + # complex persom + 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_contact_person_ssm: Contact person + complex_person_affiliation_ssm: Affiliation + complex_person_identifier_ssm: Orcid + # Complex relation + complex_relation_ssm: Related item + # Complex subject + complex_subject_ssm: Subject hyrax: account_name: My Institution Account Id directory: diff --git a/hyrax/config/routes.rb b/hyrax/config/routes.rb index 8b03d5478635511f83677c9f0338aaf82ccb4817..af02a3550c857bd20ccbf7102374202612e50424 100644 --- a/hyrax/config/routes.rb +++ b/hyrax/config/routes.rb @@ -12,6 +12,11 @@ Rails.application.routes.draw do devise_for :users mount Hydra::RoleManagement::Engine => '/' + authenticate :user, lambda { |u| u.admin? } do + require 'sidekiq/web' + mount Sidekiq::Web => '/sidekiq' + end + mount Qa::Engine => '/authorities' mount Hyrax::Engine, at: '/' resources :welcome, only: 'index' @@ -30,5 +35,7 @@ Rails.application.routes.draw do delete 'clear' end end + + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end diff --git a/hyrax/config/solr_wrapper_test.yml b/hyrax/config/solr_wrapper_test.yml index 46571e69ed2846a248f105487810d7d21fe4b6b5..82cd86755dec5ec5b11d3294c8728c4b21928f25 100644 --- a/hyrax/config/solr_wrapper_test.yml +++ b/hyrax/config/solr_wrapper_test.yml @@ -1,7 +1,10 @@ #config/solr_wrapper_test.yml -# version: 6.1.0 +version: 8.11.2 port: 8985 instance_dir: tmp/solr-test +solr_options: { + force: true +} collection: persist: false dir: solr/conf diff --git a/hyrax/lib/vocabularies/rdms.rb b/hyrax/lib/vocabularies/rdms.rb new file mode 100644 index 0000000000000000000000000000000000000000..840df402833734c3767857599f47401a59329c33 --- /dev/null +++ b/hyrax/lib/vocabularies/rdms.rb @@ -0,0 +1,30 @@ +module RDF + module Vocab + class Rdms < RDF::Vocabulary("http://www.example.com/vocabs/rdms/") + property 'Subject' # class for Rdms.subject + property 'datePublished' + property 'identifier' + property 'order' + property 'versionLabel' + # vocabulary to store funding information + property 'FundingReference' + property 'funderIdentifier' + property 'funderName' + property 'awardNumber' + property 'awardTitle' + property 'awardURI' + # CRC metadata + property 'approvalNumber' + property 'extraInformation' + property 'modality' + property 'crcResourceType' + property 'softwareVersion' + property 'subject' # of type Rdms.Subject + property 'SubjectIdentifier' + property 'SubjectSpecies' + property 'SubjectType' + property 'SubjectSex' + property 'SubjectAge' + end + end +end diff --git a/hyrax/spec/actors/hyrax/actors/crc_dataset_actor_spec.rb b/hyrax/spec/actors/hyrax/actors/crc_dataset_actor_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..bdcc0d83200289c3f1adb6ce041ce28ed74b2567 --- /dev/null +++ b/hyrax/spec/actors/hyrax/actors/crc_dataset_actor_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +require 'rails_helper' + +RSpec.describe Hyrax::Actors::CrcDatasetActor do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/controllers/hyrax/crc_datasets_controller_spec.rb b/hyrax/spec/controllers/hyrax/crc_datasets_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c288ba14599b01e669005ca6494e49173b8f1310 --- /dev/null +++ b/hyrax/spec/controllers/hyrax/crc_datasets_controller_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +require 'rails_helper' + +RSpec.describe Hyrax::CrcDatasetsController do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/factories/admin_sets.rb b/hyrax/spec/factories/admin_sets.rb new file mode 100644 index 0000000000000000000000000000000000000000..fb85e397eedba992b0cbcfc67494112fc20d175c --- /dev/null +++ b/hyrax/spec/factories/admin_sets.rb @@ -0,0 +1,30 @@ +FactoryBot.define do + factory :admin_set do + sequence(:title) { |n| ["Title #{n}"] } + + # Given the relationship between permission template and admin set, when + # an admin set is created via a factory, I believe it is appropriate to go ahead and + # create the corresponding permission template + # + # This way, we can go ahead + after(:create) do |admin_set, evaluator| + if evaluator.with_permission_template + attributes = { source_id: admin_set.id } + attributes = evaluator.with_permission_template.merge(attributes) if evaluator.with_permission_template.respond_to?(:merge) + # There is a unique constraint on permission_templates.source_id; I don't want to + # create a permission template if one already exists for this admin_set + # create(:permission_template, attributes) unless Hyrax::PermissionTemplate.find_by(source_id: admin_set.id) + create(:permission_template, attributes) unless Hyrax::PermissionTemplate.find_by(source_id: admin_set.id) + # Hyrax::Workflow::WorkflowFactory.create + Hyrax::Workflow::WorkflowImporter.load_workflows + mediated_workflow = admin_set.permission_template.available_workflows.where(name: "nims_mediated_deposit").first + Sipity::Workflow.activate!(permission_template: admin_set.permission_template, workflow_id: mediated_workflow.id) + end + end + + transient do + # false, true, or Hash with keys for permission_template + with_permission_template { false } + end + end +end \ No newline at end of file diff --git a/hyrax/spec/factories/crc_dataset.rb b/hyrax/spec/factories/crc_dataset.rb new file mode 100644 index 0000000000000000000000000000000000000000..1338f0ee25029fde7c619d6a077dc800151a4e2f --- /dev/null +++ b/hyrax/spec/factories/crc_dataset.rb @@ -0,0 +1,199 @@ +FactoryBot.define do + + factory :crc_dataset do + transient do + user { create(:user) } + # Set to true (or a hash) if you want to create an admin set + with_admin_set { false } + end + + title { ["CRC dataset"] } + access_control + + trait :open do + visibility { 'open' } + title { ["Open CRC dataset"] } + end + + trait :authenticated do + visibility { 'authenticated' } + title { ["Authenticated CRC dataset"] } + end + + trait :embargo do + visibility { 'embargo' } + title { ["Embargo CRC dataset"] } + end + + trait :lease do + visibility { 'lease' } + title { ["Leased CRC dataset"] } + end + + trait :restricted do + visibility { 'restricted' } + title { ["Restricted CRC dataset"] } + end + + trait :with_abstract do + abstract { ["Abstract-Description-123"] } + end + + trait :with_abstract_seq do + sequence(:abstract) { |n| ["Abstract-#{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_article_resource_type do + resource_type { ['Article'] } + end + + trait :with_source do + source { ['Source-123'] } + end + + trait :with_doi do + doi { "1234-1567" } + end + + trait :with_complex_person do + complex_person_attributes { + [{ + name: 'Anamika', + role: ['operator'], + orcid: '123456', + affiliation: 'University', + }] + } + end + + trait :with_complex_author do + complex_person_attributes { + [{ + name: 'Anamika', + role: ['author'], + orcid: '123456', + affiliation: 'University', + }] + } + end + + trait :with_detailed_complex_author do + complex_person_attributes { + [{ + name: 'Anamika', + first_name: 'First name', + last_name: 'Last name', + email: 'a@example.com', + role: ['author'], + orcid: '23542345234', + affiliation: 'My org' + }] + } + end + + trait :with_detailed_complex_people do + complex_person_attributes { + [{ + name: 'Anamika', + first_name: 'First name', + last_name: 'Last name', + role: ['author'], + orcid: '123456', + affiliation: 'University', + }, + { + name: 'Cee Jay', + first_name: 'First name', + last_name: 'Last name', + role: ['editor'], + orcid: '112233445566', + affiliation: 'My journal org' + }] + } + end + + trait :with_complex_date do + complex_date_attributes { + [{ + date: '1978-10-28', + description: 'Collected' + }] + } + end + + trait :with_complex_identifier do + complex_identifier_attributes { + [{ + identifier: '10.0.1111', + scheme: 'DOI' + }] + } + 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_rights do + rights_statement { + [ + 'http://creativecommons.org/publicdomain/zero/1.0/' + ] + } + end + + trait :with_complex_funding_reference do + complex_funding_reference_attributes { + [{ + funder_identifier: 'f1234', + funder_name: 'Bank', + award_number: 'a1234', + award_uri: 'http://example.com/a1234', + award_title: 'No free lunch' + }] + } + end + end +end diff --git a/hyrax/spec/factories/dataset.rb b/hyrax/spec/factories/dataset.rb new file mode 100644 index 0000000000000000000000000000000000000000..4a49f859a2a8c36d50b44efad15b41dd8c50dd4f --- /dev/null +++ b/hyrax/spec/factories/dataset.rb @@ -0,0 +1,199 @@ +FactoryBot.define do + + factory :dataset do + transient do + user { create(:user) } + # Set to true (or a hash) if you want to create an admin set + with_admin_set { false } + end + + 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_abstract do + abstract { ["Abstract-Description-123"] } + end + + trait :with_abstract_seq do + sequence(:abstract) { |n| ["Abstract-#{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_article_resource_type do + resource_type { ['Article'] } + end + + trait :with_source do + source { ['Source-123'] } + end + + trait :with_doi do + doi { "1234-1567" } + end + + trait :with_complex_person do + complex_person_attributes { + [{ + name: 'Anamika', + role: ['operator'], + orcid: '123456', + affiliation: 'University', + }] + } + end + + trait :with_complex_author do + complex_person_attributes { + [{ + name: 'Anamika', + role: ['author'], + orcid: '123456', + affiliation: 'University', + }] + } + end + + trait :with_detailed_complex_author do + complex_person_attributes { + [{ + name: 'Anamika', + first_name: 'First name', + last_name: 'Last name', + email: 'a@example.com', + role: ['author'], + orcid: '23542345234', + affiliation: 'My org' + }] + } + end + + trait :with_detailed_complex_people do + complex_person_attributes { + [{ + name: 'Anamika', + first_name: 'First name', + last_name: 'Last name', + role: ['author'], + orcid: '123456', + affiliation: 'University', + }, + { + name: 'Cee Jay', + first_name: 'First name', + last_name: 'Last name', + role: ['editor'], + orcid: '112233445566', + affiliation: 'My journal org' + }] + } + end + + trait :with_complex_date do + complex_date_attributes { + [{ + date: '1978-10-28', + description: 'Collected' + }] + } + end + + trait :with_complex_identifier do + complex_identifier_attributes { + [{ + identifier: '10.0.1111', + scheme: 'DOI' + }] + } + 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_rights do + rights_statement { + [ + 'http://creativecommons.org/publicdomain/zero/1.0/' + ] + } + end + + trait :with_complex_funding_reference do + complex_funding_reference_attributes { + [{ + funder_identifier: 'f1234', + funder_name: 'Bank', + award_number: 'a1234', + award_uri: 'http://example.com/a1234', + award_title: 'No free lunch' + }] + } + end + end +end diff --git a/hyrax/spec/factories/fedora.rb b/hyrax/spec/factories/fedora.rb new file mode 100644 index 0000000000000000000000000000000000000000..6e9919f73e8338ae05b16c3da98102fac241f914 --- /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 0000000000000000000000000000000000000000..00542d640876c3d4fbd9f4133c68fa7ec6d7cda1 --- /dev/null +++ b/hyrax/spec/factories/file_sets.rb @@ -0,0 +1,45 @@ +FactoryBot.define do + factory :file_set do + transient do + user { create(:user) } + content { File.open('spec/fixtures/csv/example.csv', 'r') } + 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 { ["Restricted File Set"] } + end + + trait :long_filename do + visibility { 'open' } + content { File.open('spec/fixtures/csv/ファイルåã®é•·ã•ãŒã‚¨ã‚¹ã‚±ãƒ¼ãƒ—後ã«256æ–‡å—以上ã«ãªã‚‹ã€é•·ã„日本語ã®ãƒ•ã‚¡ã‚¤ãƒ«åã‚’æŒã¤ãƒ•ã‚¡ã‚¤ãƒ«.csv', 'r') } + end + 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 0000000000000000000000000000000000000000..0ecda3953c3292be680d3eb61ba4e854a59b42c8 --- /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/permission_templates.rb b/hyrax/spec/factories/permission_templates.rb new file mode 100644 index 0000000000000000000000000000000000000000..776b478267ca354b9267bcf1150cc2e5daf6002b --- /dev/null +++ b/hyrax/spec/factories/permission_templates.rb @@ -0,0 +1,79 @@ +FactoryBot.define do + factory :permission_template, class: Hyrax::PermissionTemplate do + # Given that there is a one to one strong relation between permission_template and admin_set, + # with a unique index on the source_id, I don't want to have duplication in source_id + sequence(:source_id) { |n| format("%010d", n) } + + before(:create) do |permission_template, evaluator| + if evaluator.with_admin_set + source_id = permission_template.source_id + admin_set = + if source_id.present? + begin + AdminSet.find(source_id) + rescue ActiveFedora::ObjectNotFoundError + create(:admin_set, id: source_id) + end + else + create(:admin_set) + end + permission_template.source_id = admin_set.id + elsif evaluator.with_collection + source_id = permission_template.source_id + collection = + if source_id.present? + begin + Collection.find(source_id) + rescue ActiveFedora::ObjectNotFoundError + create(:collection, id: source_id) + end + else + create(:collection) + end + permission_template.source_id = collection.id + end + end + + after(:create) do |permission_template, evaluator| + if evaluator.with_workflows + Hyrax::Workflow::WorkflowImporter.load_workflow_for(permission_template: permission_template) + Sipity::Workflow.activate!(permission_template: permission_template, workflow_id: permission_template.available_workflows.pluck(:id).first) + end + if evaluator.with_active_workflow + workflow = create(:workflow, active: true, permission_template: permission_template) + create(:workflow_action, workflow: workflow) # Need to create a single action that can be taken + end + AccessHelper.create_access(permission_template, 'user', :manage, evaluator.manage_users) if evaluator.manage_users.present? + AccessHelper.create_access(permission_template, 'group', :manage, evaluator.manage_groups) if evaluator.manage_groups.present? + AccessHelper.create_access(permission_template, 'user', :deposit, evaluator.deposit_users) if evaluator.deposit_users.present? + AccessHelper.create_access(permission_template, 'group', :deposit, evaluator.deposit_groups) if evaluator.deposit_groups.present? + AccessHelper.create_access(permission_template, 'user', :view, evaluator.view_users) if evaluator.view_users.present? + AccessHelper.create_access(permission_template, 'group', :view, evaluator.view_groups) if evaluator.view_groups.present? + end + + transient do + with_admin_set { false } + with_collection { false } + with_workflows { false } + with_active_workflow { false } + manage_users { nil } + manage_groups { nil } + deposit_users { nil } + deposit_groups { nil } + view_users { nil } + view_groups { nil } + end + end + + class AccessHelper + def self.create_access(permission_template_id, agent_type, access, agent_ids) + agent_ids.each do |agent_id| + FactoryBot.create(:permission_template_access, + access, + permission_template: permission_template_id, + agent_type: agent_type, + agent_id: agent_id) + end + end + end +end diff --git a/hyrax/spec/factories/roles.rb b/hyrax/spec/factories/roles.rb new file mode 100644 index 0000000000000000000000000000000000000000..0d16fc940edd698fe6917279ce09e3e881ae2c46 --- /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/uploaded_file.rb b/hyrax/spec/factories/uploaded_file.rb new file mode 100644 index 0000000000000000000000000000000000000000..07960a7fdb7c800a8ddd518e471cd03069f41aab --- /dev/null +++ b/hyrax/spec/factories/uploaded_file.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :uploaded_file, class: Hyrax::UploadedFile do + file { Rack::Test::UploadedFile.new("#{::Rails.root}/spec/fixtures/image.jp2") } + user_id { 1 } + end +end diff --git a/hyrax/spec/factories/users.rb b/hyrax/spec/factories/users.rb new file mode 100644 index 0000000000000000000000000000000000000000..0f018df4f5fc8a3d2ae71a286151d82290664762 --- /dev/null +++ b/hyrax/spec/factories/users.rb @@ -0,0 +1,47 @@ +# 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}"} + sequence(:user_identifier) { |n| "identifier_#{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 :email do + sequence(:display_name) { |n| "Email user #{n}"} + guest { true } + employee_type_code { '60' } + end + + trait :admin do + roles { build_list :role, 1, :admin } + guest { false } + employee_type_code { '11' } + end + + end +end diff --git a/hyrax/spec/features/create_crc_dataset_spec.rb b/hyrax/spec/features/create_crc_dataset_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..753f7f2d212a7989af2463d212a7bb9ef4c182d3 --- /dev/null +++ b/hyrax/spec/features/create_crc_dataset_spec.rb @@ -0,0 +1,70 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +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 CrcDataset', js: false do + 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) { Hyrax::AdminSetCreateService.find_or_create_default_admin_set.id.to_s } + 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 + pending 'Changes may be required for this test to pass. See TODO in test.' + + visit '/dashboard' + click_link "Works" + click_link "Add new work" + + # TODO: If you generate more than one work uncomment these lines + # choose "payload_concern", option: "CrcDataset" + # click_button "Create work" + + expect(page).to have_content "Add New Crc dataset" + click_link "Files" # switch tab + expect(page).to have_content "Add files" + expect(page).to have_content "Add folder" + within('div#add-files') 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') + 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('crc_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('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/forms/hyrax/crc_dataset_form_spec.rb b/hyrax/spec/forms/hyrax/crc_dataset_form_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..4548417db6eabad3c0dcf66aad62fb35e4b20fb7 --- /dev/null +++ b/hyrax/spec/forms/hyrax/crc_dataset_form_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +require 'rails_helper' + +RSpec.describe Hyrax::CrcDatasetForm do + it "has tests" do + skip "Add your tests here" + end +end diff --git a/hyrax/spec/indexers/dataset_indexer_spec.rb b/hyrax/spec/indexers/dataset_indexer_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..853d812f5b7a29b1796e85fbee1af7ddb11cabf5 --- /dev/null +++ b/hyrax/spec/indexers/dataset_indexer_spec.rb @@ -0,0 +1,264 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'json' + +RSpec.describe DatasetIndexer do + 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' + }, { + description: 'http://bibframe.org/vocab/changeDate' + }, { + description: 'http://purl.org/dc/terms/dateAccepted', + date: '' + } + ] + + obj = build(:dataset, complex_date_attributes: dates) + + @solr_document = obj.to_solr + end + + it 'rejects blank dates' do + expect(@solr_document).not_to include('complex_date_updated_ssm') + expect(@solr_document).not_to include('complex_year_updated_sim') + expect(@solr_document).not_to include('complex_date_accepted_ssm') + expect(@solr_document).not_to include('complex_year_accepted_sim') + 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 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", + affiliation: "org", + orcid: "32123" + }, { + name: 'Big Baz', + role: "editor", + affiliation: "org 2", + orcid: "32125" + }, { + name: 'Joe Blogg', + role: "author", + }, { + first_name: ['James'], + last_name: 'Bond', + name: 'James Bond', + role: "data depositor", + affiliation: "org", + orcid: "32127" + } + ] + + 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 the identifier as a symbol' do + puts @solr_document.keys() + expect(@solr_document['complex_person_identifier_ssim']).to match_array(['32123', '32125', '32127']) + end + + it 'indexes affiliation as stored searchable' do + expect(@solr_document['complex_person_affiliation_tesim']).to match_array(['org', 'org 2']) + end + + it 'indexes affiliation as facetable' do + expect(@solr_document['complex_person_affiliation_sim']).to match_array(['org', 'org 2']) + end + end + + describe 'indexes the funding reference active triple resource with all the attributes' do + before do + fund_ref = [ + { + funder_identifier: 'f12345', + funder_name: 'Bar', + award_number: 'c', + award_title: 'Title of the award' + }, + { + funder_identifier: 'f22345', + funder_name: 'Baz', + award_number: 'a223345', + award_title: 'Another award' + } + ] + + obj = build(:dataset, complex_funding_reference_attributes: fund_ref) + + @solr_document = obj.to_solr + end + + it 'indexes as displayable' do + expect(@solr_document).to include('complex_funding_reference_ssm') + expect(JSON.parse(@solr_document['complex_funding_reference_ssm'])).not_to be_empty + end + + it 'indexes funder name as stored searchable' do + expect(@solr_document['funder_tesim']).to match_array(%w[Bar Baz]) + end + + it 'indexes funder name as facetable' do + expect(@solr_document['funder_sim']).to match_array(%w[Bar Baz]) + end + + it 'indexes award title as stored searchable' do + expect(@solr_document['award_title_tesim']).to match_array(['Title of the award', 'Another award']) + 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 +end 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 0000000000000000000000000000000000000000..64fe6bb45ef79a59c5609836b9486ddbe5089416 --- /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 \ No newline at end of file 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 0000000000000000000000000000000000000000..93882bb8634f0e0ac11343dc7290ab981a7961d0 --- /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_funding_reference_spec.rb b/hyrax/spec/models/concerns/complex_funding_reference_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..0ad885eb89d491c0c70d9f8058f8246ef3c765ad --- /dev/null +++ b/hyrax/spec/models/concerns/complex_funding_reference_spec.rb @@ -0,0 +1,102 @@ +require 'rails_helper' + +RSpec.describe ComplexFundingReference do + before do + class ExampleWork < ActiveFedora::Base + property :complex_funding_reference, predicate: ::RDF::Vocab::DataCite.fundref, + class_name:"ComplexFundingReference" + accepts_nested_attributes_for :complex_funding_reference + 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_funding_reference_attributes: [{funder_identifier: '12345'}]}) + .complex_funding_reference + .first + .funder_identifier + end + it { is_expected.to eq ['12345'] } + end + + it 'has the correct uri' do + @obj = ExampleWork.new + @obj.attributes = { + complex_funding_reference_attributes: [ + { + funder_identifier: '12345' + } + ] + } + expect(@obj.complex_funding_reference.first.id).to include('#fundref') + end + + it 'creates a fund ref active triple resource with all the attributes' do + @obj = ExampleWork.new + @obj.attributes = { + complex_funding_reference_attributes: [ + { + funder_identifier: '12456', + funder_name: 'Funder name', + award_number: 'a323', + award_uri: 'http://award.com/a323', + award_title: 'Award title for a323' + } + ] + } + expect(@obj.complex_funding_reference.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_funding_reference.first.funder_identifier).to eq ['12456'] + expect(@obj.complex_funding_reference.first.funder_name).to eq ['Funder name'] + expect(@obj.complex_funding_reference.first.award_number).to eq ['a323'] + expect(@obj.complex_funding_reference.first.award_uri).to eq ['http://award.com/a323'] + expect(@obj.complex_funding_reference.first.award_title).to eq ['Award title for a323'] + end + + describe 'when reject_if is a symbol' do + before do + class ExampleWork2 < ExampleWork + include ComplexValidation + accepts_nested_attributes_for :complex_funding_reference, reject_if: :fundref_blank + end + end + after do + Object.send(:remove_const, :ExampleWork2) + end + + it 'creates a fund ref active triple resource when any value is filled' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_funding_reference_attributes: [ + { + funder_identifier: '12456' + } + ] + } + expect(@obj.complex_funding_reference.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_funding_reference.first.funder_identifier).to eq ['12456'] + expect(@obj.complex_funding_reference.first.funder_name).to be_empty + end + + it 'rejects a fund ref active triple with no values' do + @obj = ExampleWork2.new + @obj.attributes = { + complex_funding_reference_attributes: [ + { + funder_identifier: '' + } + ] + } + expect(@obj.complex_funding_reference).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 0000000000000000000000000000000000000000..8f587ca82b4e4a57bacf0d9842258f0a1f5b05e3 --- /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_person_spec.rb b/hyrax/spec/models/concerns/complex_person_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..03001404cf3fd2b37b49367d85fd970108750a93 --- /dev/null +++ b/hyrax/spec/models/concerns/complex_person_spec.rb @@ -0,0 +1,156 @@ +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', + orcid: '1234567', + affiliation: 'Org' + }] + }).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.orcid).to eq ['1234567'] + expect(subject.affiliation).to eq ['Org'] + end + 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.orcid).to be_empty + expect(subject.affiliation).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.orcid).to be_empty + expect(subject.affiliation).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.orcid).to be_empty + expect(subject.affiliation).to be_empty + end + end + + context 'name, affiliation and role' do + let(:complex_person_attributes) do + [{ + name: 'Anamika', + affiliation: 'org', + 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.orcid).to be_empty + expect(subject.affiliation).to eq ['org'] + 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 orcid' do + let(:complex_person_attributes) { [{ orcide: 'http://orcid.org/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) { [{ affiliation: 'Some org' }] } + 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_relation_spec.rb b/hyrax/spec/models/concerns/complex_relation_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3144fd6d7b8c9d0dfec94da554d4ee66bd30cd38 --- /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/crc_dataset_spec.rb b/hyrax/spec/models/crc_dataset_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..dd88c8a1c414ec7e4d0f54f7136f87c0a3e63649 --- /dev/null +++ b/hyrax/spec/models/crc_dataset_spec.rb @@ -0,0 +1,528 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +require 'rails_helper' + +RSpec.describe CrcDataset do + it 'has human readable type for the CRC dataset' do + @obj = build(:crc_dataset) + expect(@obj.human_readable_type).to eq('Crc Dataset') + end + + describe 'date_modified' do + it 'has date_modified as singular' do + @obj = build(:crc_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(:crc_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(:crc_dataset, depositor: 'Name of depositor') + expect(@obj.depositor).to eq 'Name of depositor' + end + end + + describe 'title' do + it 'requires title' do + @obj = build(:crc_dataset, title: nil) + expect{@obj.save!}.to raise_error(ActiveFedora::RecordInvalid, + 'Validation failed: Title Your CRC dataset must have a title.') + end + + it 'has a multi valued title field' do + @obj = build(:crc_dataset, title: ['test CRC dataset']) + expect(@obj.title).to eq ['test CRC dataset'] + end + end + + describe 'alternative_title' do + it 'has alternative_title' do + @obj = build(:crc_dataset, alternative_title: ['Alternative Title']) + expect(@obj.alternative_title).to eq ['Alternative Title'] + end + end + + describe 'label' do + it 'has label as singular' do + @obj = build(:crc_dataset, label: 'Label 1') + expect(@obj.label).to eq 'Label 1' + end + end + + describe 'relative_path' do + it 'has relative_path as singular' do + @obj = build(:crc_dataset, relative_path: 'relative/path/to/file') + expect(@obj.relative_path).to eq 'relative/path/to/file' + end + end + + describe 'import_url' do + it 'has import_url as singular' do + @obj = build(:crc_dataset, import_url: 'http://example.com/import/url') + expect(@obj.import_url).to eq 'http://example.com/import/url' + end + end + + describe 'resource_type' do + it 'has resource_type' do + @obj = build(:crc_dataset, resource_type: ['CRC Dataset']) + expect(@obj.resource_type).to eq ['CRC Dataset'] + end + end + + describe 'creator' do + it 'has creator' do + @obj = build(:crc_dataset, creator: ['Creator 1']) + expect(@obj.creator).to eq ['Creator 1'] + end + end + + describe 'contributor' do + it 'has contributor' do + @obj = build(:crc_dataset, contributor: ['contributor 1']) + expect(@obj.contributor).to eq ['contributor 1'] + end + end + + describe 'description' do + it 'has description' do + @obj = build(:crc_dataset, description: ['description 1']) + expect(@obj.description).to eq ['description 1'] + end + end + + describe 'abstract' do + it 'has abstract' do + @obj = build(:crc_dataset, abstract: ['abstract 1']) + expect(@obj.abstract).to eq ['abstract 1'] + end + end + + describe 'keyword' do + it 'has keyword' do + @obj = build(:crc_dataset, keyword: ['keyword 2', '3 keyword', 'keyword 1']) + expect(@obj.keyword).to eq ['keyword 2', '3 keyword', 'keyword 1'] + end + end + + describe 'license' do + it 'has license' do + @obj = build(:crc_dataset, license: ['CC-0']) + expect(@obj.license).to eq ['CC-0'] + end + end + + describe 'rights_notes' do + it 'has rights_notes' do + @obj = build(:crc_dataset, rights_notes: ['rights_notes 1']) + expect(@obj.rights_notes).to eq ['rights_notes 1'] + end + end + + describe 'rights_statement' do + it 'has rights_statement' do + @obj = build(:crc_dataset, rights_statement: ['rights_statement 1']) + expect(@obj.rights_statement).to eq ['rights_statement 1'] + end + end + + describe 'access_right' do + it 'has access_right' do + @obj = build(:crc_dataset, access_right: ['access_right 1']) + expect(@obj.access_right).to eq ['access_right 1'] + end + end + + describe 'publisher' do + it 'has publisher' do + @obj = build(:crc_dataset, publisher: ['publisher 1']) + expect(@obj.publisher).to eq ['publisher 1'] + end + end + + describe 'date_created' do + it 'has date_created' do + @obj = build(:crc_dataset, date_created: ['date_created 1']) + expect(@obj.date_created).to eq ['date_created 1'] + end + end + + describe 'subject' do + it 'has subject' do + @obj = build(:crc_dataset, subject: ['subject 1']) + expect(@obj.subject).to eq ['subject 1'] + end + end + + describe 'language' do + it 'has language' do + @obj = build(:crc_dataset, language: ['language 1']) + expect(@obj.language).to eq ['language 1'] + end + end + + describe 'identifier' do + it 'has identifier' do + @obj = build(:crc_dataset, identifier: ['identifier 1']) + expect(@obj.identifier).to eq ['identifier 1'] + end + end + + describe 'based_near' do + it 'has based_near' do + @obj = build(:crc_dataset, based_near: ['me']) + expect(@obj.based_near).to eq ['me'] + end + end + + describe 'related_url' do + it 'has related_url' do + @obj = build(:crc_dataset, related_url: ['http://example.com/related/url']) + expect(@obj.related_url).to eq ['http://example.com/related/url'] + end + end + + describe 'bibliographic_citation' do + it 'has bibliographic_citation' do + @obj = build(:crc_dataset, bibliographic_citation: ['bibliographic_citation 1']) + expect(@obj.bibliographic_citation).to eq ['bibliographic_citation 1'] + end + end + + describe 'source' do + it 'has source' do + @obj = build(:crc_dataset, source: ['Source 1']) + expect(@obj.source).to eq ['Source 1'] + end + end + + describe 'doi' do + it 'has doi as singular' do + @obj = build(:crc_dataset, doi: '123167641234') + expect(@obj.doi).to eq '123167641234' + end + end + + describe 'complex_person' do + it 'creates a person active triple resource with name' do + @obj = build(:crc_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.affiliation).to be_empty + expect(@obj.complex_person.first.role).to be_empty + expect(@obj.complex_person.first.orcid).to be_empty + expect(@obj.complex_person.first.display_order).to be_empty + end + + it 'creates a person active triple resource with name, affiliation, orcid, role and display order' do + @obj = build(:crc_dataset, + complex_person_attributes: [{ + name: 'Anamika', + affiliation: 'Some org', + role: 'Creator', + orcid: '1231234', + display_order: 1 + }] + ) + 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.orcid).to eq ['1231234'] + expect(@obj.complex_person.first.display_order).to eq([1]) + expect(@obj.complex_person.first.affiliation).to eq(['Some org']) + end + + it 'rejects person active triple with no name and only orcid' do + @obj = build(:crc_dataset, complex_person_attributes: [{ + orcid: 'http://example.com/person/123456' + }] + ) + expect(@obj.complex_person).to be_empty + end + end + + describe 'complex_date' do + it 'creates a date active triple resource with all the attributes' do + @obj = build(:crc_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(:crc_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(:crc_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(:crc_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(:crc_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(:crc_dataset, + complex_identifier_attributes: [{ + label: 'Local' + }] + ) + expect(@obj.complex_identifier).to be_empty + end + end + + describe 'complex_funding_reference' do + it 'creates a complex funding reference active triple resource with funding reference' do + @obj = build(:crc_dataset, + complex_funding_reference_attributes: [{ + funder_identifier: 'f1234', + funder_name: 'Bank', + award_title: 'No free lunch' + }] + ) + expect(@obj.complex_funding_reference.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_funding_reference.first.id).to include('#fundref') + expect(@obj.complex_funding_reference.first.funder_identifier).to eq ['f1234'] + expect(@obj.complex_funding_reference.first.funder_name).to eq ['Bank'] + expect(@obj.complex_funding_reference.first.award_number).to be_empty + expect(@obj.complex_funding_reference.first.award_uri).to be_empty + expect(@obj.complex_funding_reference.first.award_title).to eq ['No free lunch'] + end + + it 'creates a complex funding reference active triple resource with all the attributes' do + @obj = build(:crc_dataset, + complex_funding_reference_attributes: [{ + funder_identifier: 'f1234', + funder_name: 'Bank', + award_number: 'a1234', + award_uri: 'http://award.com/a1234', + award_title: 'No free lunch' + }] + ) + expect(@obj.complex_funding_reference.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_funding_reference.first.id).to include('#fundref') + expect(@obj.complex_funding_reference.first.funder_identifier).to eq ['f1234'] + expect(@obj.complex_funding_reference.first.funder_name).to eq ['Bank'] + expect(@obj.complex_funding_reference.first.award_number).to eq ['a1234'] + expect(@obj.complex_funding_reference.first.award_uri).to eq ['http://award.com/a1234'] + expect(@obj.complex_funding_reference.first.award_title).to eq ['No free lunch'] + end + + it 'rejects a complex funding reference active triple with no attributes' do + @obj = build(:crc_dataset, + complex_funding_reference_attributes: [{ + funder_identifier: '', + funder_name: '' + }] + ) + expect(@obj.complex_funding_reference).to be_empty + end + end + + describe 'complex_relation' do + it 'creates a relation active triple resource with all the attributes' do + @obj = build(:crc_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(:crc_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(:crc_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(:crc_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(:crc_dataset, complex_relation_attributes: [{ + relationship: 'isPartOf' + }] + ) + expect(@obj.complex_relation).to be_empty + end + end + + # ------ properties from CRC metadata ------ + describe `crc_resource_type` do + it 'has crc_resource_type' do + @obj = build(:crc_dataset, crc_resource_type: 'Analysed') + expect(@obj.crc_resource_type).to eq 'Analysed' + end + end + + describe `modality` do + it 'has modality' do + @obj = build(:crc_dataset, modality: 'modality 1') + expect(@obj.modality).to eq 'modality 1' + end + end + + describe 'complex_subject' do + it 'creates a subject active triple resource with species' do + @obj = build(:crc_dataset, + complex_subject_attributes: [{ + subject_species: 'human', + }] + ) + + expect(@obj.complex_subject.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_subject.first.subject_species).to eq ['human'] + expect(@obj.complex_subject.first.subject_type).to be_empty + expect(@obj.complex_subject.first.subject_sex).to be_empty + expect(@obj.complex_subject.first.subject_age).to be_empty + end + + it 'creates a subject active triple resource with species, type, sex and age' do + @obj = build(:crc_dataset, + complex_subject_attributes: [{ + subject_species: 'human', + subject_type: 'disease', + subject_sex: 'm', + subject_age: '22' + }] + ) + expect(@obj.complex_subject.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_subject.first.subject_species).to eq ['human'] + expect(@obj.complex_subject.first.subject_type).to eq ['disease'] + expect(@obj.complex_subject.first.subject_sex).to eq ['m'] + expect(@obj.complex_subject.first.subject_age).to eq ['22'] + end + + end + + describe 'approval_number' do + it 'has approval_number' do + @obj = build(:crc_dataset, approval_number: 'approval_number 1') + expect(@obj.approval_number).to eq 'approval_number 1' + end + end + + describe 'extra_information' do + it 'has extra_information' do + @obj = build(:crc_dataset, extra_information: ['extra_information']) + expect(@obj.extra_information).to eq ['extra_information'] + end + end + + describe `software_version` do + it 'has software_version' do + @obj = build(:crc_dataset, software_version: ['software_version 1']) + expect(@obj.software_version).to eq ['software_version 1'] + end + end + + # ------ properties from DublinCore metadata ------ + describe `coverage` do + it 'has coverage' do + @obj = build(:crc_dataset, coverage: ['Europe']) + expect(@obj.coverage).to eq ['Europe'] + end + end + +end diff --git a/hyrax/spec/models/dataset_spec.rb b/hyrax/spec/models/dataset_spec.rb index 77a91571f0ebf6de4ef3ddbdb176076508f885c0..e3a1a340cc6e8286a787bb8751070d0a5793e05f 100644 --- a/hyrax/spec/models/dataset_spec.rb +++ b/hyrax/spec/models/dataset_spec.rb @@ -3,7 +3,449 @@ require 'rails_helper' RSpec.describe Dataset do - it "has tests" do - skip "Add your tests here" + 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 'alternative_title' do + it 'has alternative_title' do + @obj = build(:dataset, alternative_title: ['Alternative Title']) + expect(@obj.alternative_title).to eq ['Alternative Title'] + 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 '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 '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 'resource_type' do + it 'has resource_type' do + @obj = build(:dataset, resource_type: ['Dataset']) + expect(@obj.resource_type).to eq ['Dataset'] + 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 'contributor' do + it 'has contributor' do + @obj = build(:dataset, contributor: ['contributor 1']) + expect(@obj.contributor).to eq ['contributor 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 'abstract' do + it 'has abstract' do + @obj = build(:dataset, abstract: ['abstract 1']) + expect(@obj.abstract).to eq ['abstract 1'] + end + end + + describe 'keyword' do + it 'has keyword' do + @obj = build(:dataset, keyword: ['keyword 2', '3 keyword', 'keyword 1']) + expect(@obj.keyword).to eq ['keyword 2', '3 keyword', 'keyword 1'] + end + end + + describe 'license' do + it 'has license' do + @obj = build(:dataset, license: ['CC-0']) + expect(@obj.license).to eq ['CC-0'] + end + end + + describe 'rights_notes' do + it 'has rights_notes' do + @obj = build(:dataset, rights_notes: ['rights_notes 1']) + expect(@obj.rights_notes).to eq ['rights_notes 1'] + 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 'access_right' do + it 'has access_right' do + @obj = build(:dataset, access_right: ['access_right 1']) + expect(@obj.access_right).to eq ['access_right 1'] + 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 '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 'subject' do + it 'has subject' do + @obj = build(:dataset, subject: ['subject 1']) + expect(@obj.subject).to eq ['subject 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 'identifier' do + it 'has identifier' do + @obj = build(:dataset, identifier: ['identifier 1']) + expect(@obj.identifier).to eq ['identifier 1'] + 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 '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 '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 'source' do + it 'has source' do + @obj = build(:dataset, source: ['Source 1']) + expect(@obj.source).to eq ['Source 1'] + end + end + + describe 'doi' do + it 'has doi as singular' do + @obj = build(:dataset, doi: '123167641234') + expect(@obj.doi).to eq '123167641234' + 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.affiliation).to be_empty + expect(@obj.complex_person.first.role).to be_empty + expect(@obj.complex_person.first.orcid).to be_empty + expect(@obj.complex_person.first.display_order).to be_empty + end + + it 'creates a person active triple resource with name, affiliation, orcid, role and display order' do + @obj = build(:dataset, + complex_person_attributes: [{ + name: 'Anamika', + affiliation: 'Some org', + role: 'Creator', + orcid: '1231234', + display_order: 1 + }] + ) + 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.orcid).to eq ['1231234'] + expect(@obj.complex_person.first.display_order).to eq([1]) + expect(@obj.complex_person.first.affiliation).to eq(['Some org']) + end + + it 'rejects person active triple with no name and only orcid' do + @obj = build(:dataset, complex_person_attributes: [{ + orcid: 'http://example.com/person/123456' + }] + ) + expect(@obj.complex_person).to be_empty + 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_funding_reference' do + it 'creates a complex funding reference active triple resource with funding reference' do + @obj = build(:dataset, + complex_funding_reference_attributes: [{ + funder_identifier: 'f1234', + funder_name: 'Bank', + award_title: 'No free lunch' + }] + ) + expect(@obj.complex_funding_reference.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_funding_reference.first.id).to include('#fundref') + expect(@obj.complex_funding_reference.first.funder_identifier).to eq ['f1234'] + expect(@obj.complex_funding_reference.first.funder_name).to eq ['Bank'] + expect(@obj.complex_funding_reference.first.award_number).to be_empty + expect(@obj.complex_funding_reference.first.award_uri).to be_empty + expect(@obj.complex_funding_reference.first.award_title).to eq ['No free lunch'] + end + + it 'creates a complex funding reference active triple resource with all the attributes' do + @obj = build(:dataset, + complex_funding_reference_attributes: [{ + funder_identifier: 'f1234', + funder_name: 'Bank', + award_number: 'a1234', + award_uri: 'http://award.com/a1234', + award_title: 'No free lunch' + }] + ) + expect(@obj.complex_funding_reference.first).to be_kind_of ActiveTriples::Resource + expect(@obj.complex_funding_reference.first.id).to include('#fundref') + expect(@obj.complex_funding_reference.first.funder_identifier).to eq ['f1234'] + expect(@obj.complex_funding_reference.first.funder_name).to eq ['Bank'] + expect(@obj.complex_funding_reference.first.award_number).to eq ['a1234'] + expect(@obj.complex_funding_reference.first.award_uri).to eq ['http://award.com/a1234'] + expect(@obj.complex_funding_reference.first.award_title).to eq ['No free lunch'] + end + + it 'rejects a complex funding reference active triple with no attributes' do + @obj = build(:dataset, + complex_funding_reference_attributes: [{ + funder_identifier: '', + funder_name: '' + }] + ) + expect(@obj.complex_funding_reference).to be_empty + 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 + end diff --git a/hyrax/spec/presenters/dataset_presenter_spec.rb b/hyrax/spec/presenters/dataset_presenter_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..812481265c795b4ff1680f15eb6c91f079bf70f4 --- /dev/null +++ b/hyrax/spec/presenters/dataset_presenter_spec.rb @@ -0,0 +1,101 @@ +require 'rails_helper' + +RSpec.describe Hyrax::DatasetPresenter do + DatabaseCleaner.clean + let(:dataset) { create(:dataset, :open, :with_alternative_title, depositor: 'despositor') } + let(:solr_document) { SolrDocument.new(dataset.to_solr) } + let(:host) { double(host: 'http://example.org') } + let(:user) { nil } + let(:presenter) { described_class.new(solr_document, Ability.new(user), host) } + + before do + DatabaseCleaner.clean + end + + describe '#export_as_ttl' do + subject { presenter.export_as_ttl } + let(:export_regex) { + [ + %r(<http://example.org/concern/datasets/#{dataset.id}> a), + %r(<http://projecthydra.org/works/models#Work>), + %r(<http://pcdm.org/models#Object>), + %r(<http://purl.org/dc/terms/title> "Open Dataset";), + %r(<http://purl.org/dc/terms/alternative> "Alternative-Title-123";), + %r(<http://www.w3.org/ns/auth/acl#accessControl> <http://example.org/catalog/([a-f0-9\\-]*)+>;), + %r(<info:fedora/fedora-system:def/model#hasModel> "Dataset" .) + ] + } + let(:abstract_regex) { %r(<http://purl.org/dc/elements/1.1/description> "Abstract-Description-123";) } + let(:supervisor_regex) { %r(<http://www.nims.go.jp/vocabs/ngdr/supervisor-approval> "Professor-Supervisor-Approval";) } + let(:depositor_regex) { %r(<http://example.org/concern/datasets/#{dataset.id}> <http://id.loc.gov/vocabulary/relators/dpt> "depositor") } + + it 'exports' do + export_regex.each do |regex| + expect(subject).to match(regex) + end + end + + context 'anonymous user' do + it { is_expected.not_to match(abstract_regex) } + it { is_expected.not_to match(supervisor_regex) } + it { is_expected.not_to match(depositor_regex) } + end + end + + describe '#export_as_nt' do + subject { presenter.export_as_nt } + let(:export_regex) { + [ + %r(<http://example.org/concern/datasets/#{dataset.id}> <http://www.w3.org/ns/auth/acl#accessControl> <http://example.org/catalog/([a-f0-9\\-]*)+>), + %r(<http://example.org/concern/datasets/#{dataset.id}> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://projecthydra.org/works/models#Work>), + %r(<http://example.org/concern/datasets/#{dataset.id}> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://pcdm.org/models#Object>), + %r(<http://example.org/concern/datasets/#{dataset.id}> <info:fedora/fedora-system:def/model#hasModel> "Dataset"), + %r(<http://example.org/concern/datasets/#{dataset.id}> <http://purl.org/dc/terms/alternative> "Alternative-Title-123"), + %r(<http://example.org/concern/datasets/#{dataset.id}> <http://purl.org/dc/terms/title> "Open Dataset") + ] + } + let(:abstract_regex) { %r(<http://example.org/concern/datasets/#{dataset.id}> <http://purl.org/dc/elements/1.1/description> "Abstract-Description-123") } + let(:supervisor_regex) { %r(<http://example.org/concern/datasets/#{dataset.id}> <http://www.nims.go.jp/vocabs/ngdr/supervisor-approval> "Professor-Supervisor-Approval") } + let(:depositor_regex) { %r(<http://example.org/concern/publications/#{dataset.id}> <http://id.loc.gov/vocabulary/relators/dpt> "depositor") } + + it 'exports' do + export_regex.each do |regex| + expect(subject).to match(regex) + end + end + + context 'anonymous user' do + it { is_expected.not_to match(abstract_regex) } + it { is_expected.not_to match(supervisor_regex) } + it { is_expected.not_to match(depositor_regex) } + end + end + + describe '#export_as_jsonld' do + subject { JSON.parse(presenter.export_as_jsonld) } + # NB: it is important to use => rather than a colon: - otherwise the strings get symbolised + + it 'exports' do + expect(subject["@context"]).to include( + "pcdmterms" => "http://pcdm.org/models#", + "worksterms" => "http://projecthydra.org/works/models#", + "dc" => "http://purl.org/dc/terms/", + "acl" => "http://www.w3.org/ns/auth/acl#", + "system" => "info:fedora/fedora-system:", + "model" => "system:def/model#" + ) + expect(subject["@id"]).to eql "http://example.org/concern/datasets/#{dataset.id}" + expect(subject["dc:title"]).to eql "Open Dataset" + expect(subject["dc:alternative"]).to eql "Alternative-Title-123" + expect(subject["model:hasModel"]).to eql "Dataset" + expect(subject["acl:accessControl"]).to include("@id") + expect(subject["@type"]).to match_array %w(pcdm:Object worksterms:Work) + end + + context 'anonymous user' do + it { is_expected.not_to include("dc11:description" => "Abstract-Description-123") } + it { is_expected.not_to include("nimsrdp:supervisor-approval" => "Professor-Supervisor-Approval") } + it { is_expected.not_to include("marcrelators:dpt" => "depositor") } + end + end +end diff --git a/hyrax/spec/presenters/hyrax/crc_dataset_presenter_spec.rb b/hyrax/spec/presenters/hyrax/crc_dataset_presenter_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..bd60a0ea7b0497e376a17969c73c376a9357dae3 --- /dev/null +++ b/hyrax/spec/presenters/hyrax/crc_dataset_presenter_spec.rb @@ -0,0 +1,9 @@ +# Generated via +# `rails generate hyrax:work CrcDataset` +require 'rails_helper' + +RSpec.describe Hyrax::CrcDatasetPresenter 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 b6317b5a3431da55461a28b456cd3b4798691513..6e7668258b4bad5ea1f639e787791b7d55b23646 100644 --- a/hyrax/spec/rails_helper.rb +++ b/hyrax/spec/rails_helper.rb @@ -1,10 +1,15 @@ # This file is copied to spec/ when you run 'rails generate rspec:install' require 'spec_helper' ENV['RAILS_ENV'] ||= 'test' -require_relative '../config/environment' +require File.expand_path('../../config/environment', __FILE__) # 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 @@ -33,6 +38,8 @@ end RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" + config.include Devise::Test::ControllerHelpers, type: :view + config.include Devise::Test::ControllerHelpers, type: :controller # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false 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 0000000000000000000000000000000000000000..88692589a7c544cbb001d0b2fbef868f0f6d918e --- /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: 'Collected') + 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_funding_reference_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_funding_reference_attribute_renderer_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..24def1b62a0f262d9735206e63c3324f06fa3aa0 --- /dev/null +++ b/hyrax/spec/renderers/nested_funding_reference_attribute_renderer_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + +RSpec.describe NestedFundingReferenceAttributeRenderer do + let(:html) { described_class.new('Funding Reference', nested_value.to_json).render } + let(:nested_value) { build(:dataset, :with_complex_funding_reference).complex_funding_reference.first } + subject { Capybara.string(html) } + + it 'generates the correct fields' do + is_expected.to have_css('th', text: 'Funding reference') + + is_expected.to have_css('div.row label', text: 'Funder identifier') + is_expected.to have_css('div.row', text: 'f1234') + + is_expected.to have_css('div.row label', text: 'Funder name') + is_expected.to have_css('div.row', text: 'Bank') + + is_expected.to have_css('div.row label', text: 'Award number') + is_expected.to have_css('div.row', text: 'a1234') + + is_expected.to have_css('div.row label', text: 'Award title') + is_expected.to have_css('div.row', text: 'No free lunch') + 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 0000000000000000000000000000000000000000..64425b32b5c2c1b252c640febf5b290105e1699e --- /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_person_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_person_attribute_renderer_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..13d45eb4876aff21893acc5aeeaa032f93e9e81a --- /dev/null +++ b/hyrax/spec/renderers/nested_person_attribute_renderer_spec.rb @@ -0,0 +1,35 @@ +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: 'Affiliation') + is_expected.to have_css('div.row', text: 'University') + + 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: 'ORCID') + is_expected.to have_css('div.row', text: '123456') + 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_relation_attribute_renderer_spec.rb b/hyrax/spec/renderers/nested_relation_attribute_renderer_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..64eb22f33a9a58595926bd443e2a7e9afda3b3ef --- /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/spec_helper.rb b/hyrax/spec/spec_helper.rb index a0d4080592b01aca1eaf0946a567fc81bae334f2..30bc7f28f569b67615aac2c7804d14d2b85c43f7 100644 --- a/hyrax/spec/spec_helper.rb +++ b/hyrax/spec/spec_helper.rb @@ -1,94 +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 https://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: - # https://relishapp.com/rspec/rspec-core/docs/configuration/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 0000000000000000000000000000000000000000..4f266ff94213efe933483f4f3ae7f69655547cb5 --- /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 0000000000000000000000000000000000000000..83f54bf37bf7324312d437e42b37c90923a87ba9 --- /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/datasets/_attribute_rows.html_spec.rb b/hyrax/spec/views/hyrax/datasets/_attribute_rows.html_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..37b7b2a2d24115b8f107d742d0d9b980b451f6c9 --- /dev/null +++ b/hyrax/spec/views/hyrax/datasets/_attribute_rows.html_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' +include Warden::Test::Helpers + +RSpec.describe 'hyrax/datasets/_attribute_rows' do + user = User.find_by(email: 'admin@hyrax') + let(:partial) { 'hyrax/datasets/attribute_rows' } + let(:dataset) { create(:dataset, :open, :with_doi, :with_complex_person, :with_complex_date, + :with_complex_identifier, :with_complex_funding_reference, :with_complex_relation) } + 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 'authenticated user' do + it 'shows the correct metadata' do + # doi + expect(rendered).to have_content('1234-1567') + # complex person + expect(rendered).to have_content('Anamika') + expect(rendered).to have_content('operator') + expect(rendered).to have_content('University') + # complex identifier + expect(rendered).to have_content('doi:10.0.1111') + # complex relation + expect(rendered).to have_content('A relation label') + expect(rendered).to have_content('is new version of') + # complex funder reference + expect(rendered).to have_content('f1234') + expect(rendered).to have_content('Bank') + expect(rendered).to have_content('a1234') + expect(rendered).to have_content('http://example.com/a1234') + expect(rendered).to have_content('No free lunch') + # Abstract/Description is not displayed in this table partial + expect(rendered).not_to have_content('Abstract-Description-123') + end + end +end