diff --git a/.gitignore b/.gitignore
index d3fd6cc3ab..5c5f043efe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -66,6 +66,7 @@ public/javascripts/i18n.js
public/javascripts/translations.js
public/stylesheets/*_cached.css
public/system/
+public/sitemaps/*
public/assets/
public/assets_dev/
diff --git a/Gemfile b/Gemfile
index fd40d4e720..619ca2babd 100644
--- a/Gemfile
+++ b/Gemfile
@@ -109,6 +109,7 @@ gem 'ransack'
gem 'terser', '~> 1.1', '>= 1.1.1'
+
# Rails 4 upgrade
gem 'activerecord-session_store'
gem 'rails-observers'
@@ -177,6 +178,8 @@ group :development do
gem 'web-console', '>= 4.1.0'
gem 'rack-mini-profiler', '~> 2.0'
+ gem "flamegraph", "~> 0.9.5"
+ gem "stackprof", "~> 0.2.25"
gem 'listen', '~> 3.3'
end
@@ -202,3 +205,5 @@ group :test, :development do
gem 'teaspoon'
gem 'teaspoon-mocha'
end
+
+gem "sitemap_generator", "~> 6.3"
diff --git a/Gemfile.lock b/Gemfile.lock
index b2797432af..acecd6c9c8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -51,40 +51,40 @@ GEM
remote: https://rubygems.org/
specs:
RedCloth (4.3.2)
- actioncable (6.1.7.3)
- actionpack (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ actioncable (6.1.7.6)
+ actionpack (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
- actionmailbox (6.1.7.3)
- actionpack (= 6.1.7.3)
- activejob (= 6.1.7.3)
- activerecord (= 6.1.7.3)
- activestorage (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ actionmailbox (6.1.7.6)
+ actionpack (= 6.1.7.6)
+ activejob (= 6.1.7.6)
+ activerecord (= 6.1.7.6)
+ activestorage (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
mail (>= 2.7.1)
- actionmailer (6.1.7.3)
- actionpack (= 6.1.7.3)
- actionview (= 6.1.7.3)
- activejob (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ actionmailer (6.1.7.6)
+ actionpack (= 6.1.7.6)
+ actionview (= 6.1.7.6)
+ activejob (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (6.1.7.3)
- actionview (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ actionpack (6.1.7.6)
+ actionview (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
- actiontext (6.1.7.3)
- actionpack (= 6.1.7.3)
- activerecord (= 6.1.7.3)
- activestorage (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ actiontext (6.1.7.6)
+ actionpack (= 6.1.7.6)
+ activerecord (= 6.1.7.6)
+ activestorage (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
nokogiri (>= 1.8.5)
- actionview (6.1.7.3)
- activesupport (= 6.1.7.3)
+ actionview (6.1.7.6)
+ activesupport (= 6.1.7.6)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
@@ -94,14 +94,14 @@ GEM
activemodel (>= 4.1, < 7.1)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
- activejob (6.1.7.3)
- activesupport (= 6.1.7.3)
+ activejob (6.1.7.6)
+ activesupport (= 6.1.7.6)
globalid (>= 0.3.6)
- activemodel (6.1.7.3)
- activesupport (= 6.1.7.3)
- activerecord (6.1.7.3)
- activemodel (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ activemodel (6.1.7.6)
+ activesupport (= 6.1.7.6)
+ activerecord (6.1.7.6)
+ activemodel (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
activerecord-import (1.3.0)
activerecord (>= 4.2)
activerecord-session_store (2.0.0)
@@ -110,14 +110,14 @@ GEM
multi_json (~> 1.11, >= 1.11.2)
rack (>= 2.0.8, < 3)
railties (>= 5.2.4.1)
- activestorage (6.1.7.3)
- actionpack (= 6.1.7.3)
- activejob (= 6.1.7.3)
- activerecord (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ activestorage (6.1.7.6)
+ actionpack (= 6.1.7.6)
+ activejob (= 6.1.7.6)
+ activerecord (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
marcel (~> 1.0)
mini_mime (>= 1.1.0)
- activesupport (6.1.7.3)
+ activesupport (6.1.7.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@@ -286,6 +286,7 @@ GEM
loofah (>= 2.3.1)
sax-machine (>= 1.0)
ffi (1.15.5)
+ flamegraph (0.9.5)
fssm (0.2.10)
gem-licenses (0.2.2)
gitlab_omniauth-ldap (2.2.0)
@@ -293,8 +294,8 @@ GEM
omniauth (>= 1.3, < 3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
- globalid (1.1.0)
- activesupport (>= 5.0)
+ globalid (1.2.1)
+ activesupport (>= 6.1)
google-analytics-rails (1.1.1)
gyoku (0.4.6)
builder (>= 2.1.2)
@@ -458,8 +459,9 @@ GEM
mimemagic (0.3.10)
nokogiri (~> 1)
rake
- mini_mime (1.1.2)
- minitest (5.18.0)
+ mini_mime (1.1.5)
+ mini_portile2 (2.8.4)
+ minitest (5.20.0)
minitest-reporters (1.5.0)
ansi
builder
@@ -478,7 +480,7 @@ GEM
net-http-digest_auth (1.4.1)
net-http-persistent (4.0.1)
connection_pool (~> 2.2)
- net-imap (0.3.4)
+ net-imap (0.3.7)
date
net-protocol
net-ldap (0.17.1)
@@ -491,6 +493,7 @@ GEM
netrc (0.11.0)
nio4r (2.5.9)
nokogiri (1.14.5)
+ mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nori (1.1.5)
oauth2 (2.0.9)
@@ -563,7 +566,7 @@ GEM
nio4r (~> 2.0)
pyu-ruby-sasl (0.0.3.3)
racc (1.7.1)
- rack (2.2.7)
+ rack (2.2.8)
rack-attack (6.6.0)
rack (>= 1.0, < 3)
rack-cors (1.1.1)
@@ -580,26 +583,26 @@ GEM
rack
rack-test (2.1.0)
rack (>= 1.3)
- rails (6.1.7.3)
- actioncable (= 6.1.7.3)
- actionmailbox (= 6.1.7.3)
- actionmailer (= 6.1.7.3)
- actionpack (= 6.1.7.3)
- actiontext (= 6.1.7.3)
- actionview (= 6.1.7.3)
- activejob (= 6.1.7.3)
- activemodel (= 6.1.7.3)
- activerecord (= 6.1.7.3)
- activestorage (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ rails (6.1.7.6)
+ actioncable (= 6.1.7.6)
+ actionmailbox (= 6.1.7.6)
+ actionmailer (= 6.1.7.6)
+ actionpack (= 6.1.7.6)
+ actiontext (= 6.1.7.6)
+ actionview (= 6.1.7.6)
+ activejob (= 6.1.7.6)
+ activemodel (= 6.1.7.6)
+ activerecord (= 6.1.7.6)
+ activestorage (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
bundler (>= 1.15.0)
- railties (= 6.1.7.3)
+ railties (= 6.1.7.6)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1)
activesupport (>= 5.0.1.rc1)
- rails-dom-testing (2.1.1)
+ rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
@@ -621,9 +624,9 @@ GEM
json
require_all (~> 3.0)
ruby-progressbar
- railties (6.1.7.3)
- actionpack (= 6.1.7.3)
- activesupport (= 6.1.7.3)
+ railties (6.1.7.6)
+ actionpack (= 6.1.7.6)
+ activesupport (= 6.1.7.6)
method_source
rake (>= 12.2)
thor (~> 1.0)
@@ -828,6 +831,8 @@ GEM
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.3)
+ sitemap_generator (6.3.0)
+ builder (~> 3.0)
slop (3.6.0)
snaky_hash (2.0.0)
hashie
@@ -844,7 +849,7 @@ GEM
sparql-client (3.2.0)
net-http-persistent (~> 4.0, >= 4.0.1)
rdf (~> 3.2)
- sprockets (4.2.0)
+ sprockets (4.2.1)
concurrent-ruby (~> 1.0)
rack (>= 2.2.4, < 4)
sprockets-rails (3.4.2)
@@ -852,6 +857,7 @@ GEM
activesupport (>= 5.2)
sprockets (>= 3.0.0)
sqlite3 (1.4.2)
+ stackprof (0.2.25)
stringio (3.0.1)
sunspot (2.6.0)
pr_geohash (~> 1.0)
@@ -882,7 +888,7 @@ GEM
tilt (2.0.10)
time (0.2.2)
date
- timeout (0.3.2)
+ timeout (0.4.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
ucf (2.0.2)
@@ -930,7 +936,7 @@ GEM
hashdiff (>= 0.4.0, < 2.0.0)
webrick (1.7.0)
webrobots (0.1.2)
- websocket-driver (0.7.5)
+ websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
whenever (1.0.0)
@@ -943,7 +949,7 @@ GEM
rake (>= 0.8.7)
yard (0.9.27)
webrick (~> 1.7.0)
- zeitwerk (2.6.8)
+ zeitwerk (2.6.11)
zip-container (4.0.2)
rubyzip (~> 2.0.0)
@@ -990,6 +996,7 @@ DEPENDENCIES
exception_notification
factory_bot (~> 6.2.1)
feedjira
+ flamegraph (~> 0.9.5)
fleximage!
fssm
gem-licenses
@@ -1073,8 +1080,10 @@ DEPENDENCIES
seedbank
simple-spreadsheet-extractor (~> 0.18.0)
simplecov
+ sitemap_generator (~> 6.3)
sprockets-rails
sqlite3 (~> 1.4)
+ stackprof (~> 0.2.25)
stringio (= 3.0.1)
sunspot_matchers
sunspot_rails
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 4f80e6a46e..eeb6c760ef 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -56,7 +56,7 @@
//= require calendar
//= require inplace
//= require strain
-//= require checkbox
+//= require batch_asset_selection
//= require cytoscape.js-2.5.0/cytoscape
//= require cytoscape_isa_graph
//= require bives
@@ -75,3 +75,4 @@
//= require git
//= require jquery.splitter/jquery.splitter.min
//= require select2.full.min
+//= require licenses
diff --git a/app/assets/javascripts/application_shared.js.erb b/app/assets/javascripts/application_shared.js.erb
index a3c400fb40..3b8c59fe21 100644
--- a/app/assets/javascripts/application_shared.js.erb
+++ b/app/assets/javascripts/application_shared.js.erb
@@ -399,6 +399,8 @@ $j(document).ready(function () {
$j('#sidebar-toggle').click(Sidebar.toggle);
$j('#sidebar-close').click(Sidebar.toggle);
$j(document).on('click', '.sidebar-backdrop', Sidebar.toggle);
+
+ Licenses.init();
});
var URL_ROOT = '<%= Rails.application.config.relative_url_root %>';
diff --git a/app/assets/javascripts/batch_asset_selection.js b/app/assets/javascripts/batch_asset_selection.js
new file mode 100644
index 0000000000..e6bb2e2c27
--- /dev/null
+++ b/app/assets/javascripts/batch_asset_selection.js
@@ -0,0 +1,121 @@
+$j(document).ready(function () {
+ $j('.batch-selection-select-children').click(BatchAssetSelection.selectChildren);
+ $j('.batch-selection-deselect-children').click(BatchAssetSelection.deselectChildren);
+ $j('.batch-selection-collapse-children').click(BatchAssetSelection.collapseRecursively);
+ $j('.batch-selection-expand-children').click(BatchAssetSelection.expandRecursively);
+ $j('.batch-selection-show-permissions').click(function (event) {
+ event.preventDefault();
+ $j('.batch-selection-permission-list', $j(this).closest('.batch-selection-scope')).show();
+ })
+ $j('.batch-selection-hide-permissions').click(function (event) {
+ event.preventDefault();
+ $j('.batch-selection-permission-list', $j(this).closest('.batch-selection-scope')).hide();
+ })
+ $j('.batch-selection-hide-blocked').click(BatchAssetSelection.hideBlocked).click(); // Trigger on page load
+ $j('.batch-selection-show-blocked').click(BatchAssetSelection.showBlocked);
+ $j('.batch-selection-collapse-toggle').click(function () {
+ BatchAssetSelection.toggleCollapse(this);
+ return false;
+ });
+ $j('.batch-selection-check-btn').click(function (event) {
+ if (event.target.nodeName.includes('BUTTON')) {
+ $j(this).find(':checkbox').click();
+ }
+ });
+ $j('.batch-selection-check-btn :checkbox').click(function () {
+ BatchAssetSelection.checkRepeatedItems(this.className, this.checked);
+ });
+ $j('.batch-selection-managed-by-toggle').click(function (event) {
+ event.preventDefault();
+ $j('.batch-selection-managed-by-list:first', $j(this).closest('.batch-selection-scope')).toggle();
+ });
+ $j('.batch-selection-permissions-toggle').click(function (event) {
+ event.preventDefault();
+ $j('.batch-selection-permission-list:first', $j(this).closest('.batch-selection-scope')).toggle();
+ });
+});
+
+const BatchAssetSelection = {
+ blockedSelectors: '.not-visible, .not-manageable, .already-published',
+ selectChildren: function (event) {
+ event.preventDefault();
+ BatchAssetSelection.setChildren($j(this).closest('.batch-selection-scope'), true);
+ },
+
+ deselectChildren: function (event) {
+ event.preventDefault();
+ BatchAssetSelection.setChildren($j(this).closest('.batch-selection-scope'), false);
+ },
+
+ setChildren: function (scope, value) {
+ const children = $j(':checkbox', scope);
+ const classes = new Set();
+ for (let child of children) {
+ classes.add(child.className);
+ }
+
+ classes.forEach(c => BatchAssetSelection.checkRepeatedItems(c, value));
+ },
+
+ checkRepeatedItems: function (className, check) {
+ document.getElementById('batch-asset-selection')
+ .querySelectorAll('.' + className).forEach(e => e.checked = check);
+ },
+
+ toggleManagers: function () {
+ $j('.batch-selection-managed-by-list', $j(this).closest('.batch-selection-asset')).toggle();
+
+ return false;
+ },
+
+ toggleCollapse: function (element, state) {
+ if (state === undefined) {
+ state = !element.classList.contains('open');
+ }
+ element.classList.toggle('open', state);
+ $j(element).closest('.batch-selection-scope').children('.batch-selection-collapse').toggle(state);
+ },
+
+ collapseRecursively: function () {
+ const scope = $j(this).closest('.batch-selection-scope').children('.batch-selection-collapse');
+ const toggles = $j('.batch-selection-collapse-toggle', scope);
+ for (let toggle of toggles) {
+ BatchAssetSelection.toggleCollapse(toggle, false);
+ }
+
+ return false;
+ },
+
+ expandRecursively: function () {
+ const scope = $j(this).closest('.batch-selection-scope').children('.batch-selection-collapse');
+ const toggles = $j('.batch-selection-collapse-toggle', scope);
+ for (let toggle of toggles) {
+ BatchAssetSelection.toggleCollapse(toggle, true);
+ }
+
+ return false;
+ },
+
+ hideBlocked: function () {
+ const children = $j(this).closest('.batch-selection-scope')
+ .find(BatchAssetSelection.blockedSelectors)
+ .closest('.batch-selection-asset');
+ for (let child of children) {
+ const element = $j(child);
+ // Don't hide if any non-blocked children
+ if (!$j(':checkbox', element).length) {
+ element.hide();
+ }
+ }
+
+ return false;
+ },
+
+ showBlocked: function () {
+ $j(this).closest('.batch-selection-scope')
+ .find(BatchAssetSelection.blockedSelectors)
+ .closest('.batch-selection-asset').show();
+
+ return false;
+ }
+}
diff --git a/app/assets/javascripts/checkbox.js b/app/assets/javascripts/checkbox.js
deleted file mode 100644
index d5751b2fa2..0000000000
--- a/app/assets/javascripts/checkbox.js
+++ /dev/null
@@ -1,42 +0,0 @@
-$j(document).ready(function () {
- $j("a.selectChildren").click(function (event) {
- event.preventDefault();
- selectChildren(this,$j(this).data("cb_parent_selector"))
- })
- $j("a.deselectChildren").click(function (event) {
- event.preventDefault();
- deselectChildren(this,$j(this).data("cb_parent_selector"))
- })
- $j('#jstree').on('click', 'a.selectChildren', function (event) {
- event.preventDefault();
- selectChildren(this,$j(this).data("cb_parent_selector"))
- })
- $j('#jstree').on('click', 'a.deselectChildren', function (event) {
- event.preventDefault();
- deselectChildren(this,$j(this).data("cb_parent_selector"))
- })
-})
-
-function selectChildren(select_all_element,cb_parent_selector){
- let children_checkboxes = $j(':checkbox', $j(select_all_element).parents(cb_parent_selector))
- for(let checkbox of children_checkboxes){
- let checkbox_element = { className: checkbox.className, checked: true }
- checkRepeatedItems(checkbox_element)
- }
-}
-
-function deselectChildren(deselect_all_element,cb_parent_selector){
- let children_checkboxes = $j(':checkbox', $j(deselect_all_element).parents(cb_parent_selector))
- for(let checkbox of children_checkboxes){
- let checkbox_element = { className: checkbox.className, checked: false }
- checkRepeatedItems(checkbox_element)
- }
-}
-
-function checkRepeatedItems(checkbox_element) {
- let repeated_elements = document.getElementsByClassName(checkbox_element.className)
- let check = checkbox_element.checked
- for(let element of repeated_elements){
- element.checked = check
- }
-}
\ No newline at end of file
diff --git a/app/assets/javascripts/licenses.js b/app/assets/javascripts/licenses.js
new file mode 100644
index 0000000000..cd3e115e8f
--- /dev/null
+++ b/app/assets/javascripts/licenses.js
@@ -0,0 +1,23 @@
+var Licenses = {
+ init: function () {
+ $j('[data-seek-license-select="true"]').on('select2:select', Licenses.displayUrl);
+ $j('[data-seek-license-select="true"]').trigger('select2:select');
+ },
+
+ displayUrl: function () {
+ var element = $j('option:selected', $j(this));
+ var link = $j('#license-url');
+ if (link.length) {
+ var block = link.parents('.license-url-block');
+
+ if (element.data('url')) {
+ block.show();
+ } else {
+ block.hide();
+ }
+
+ link.attr('href', element.data('url'));
+ link.html(element.data('url'));
+ }
+ }
+}
diff --git a/app/assets/javascripts/single_page/dynamic_table.js.erb b/app/assets/javascripts/single_page/dynamic_table.js.erb
index dbcbbb2601..cdd63249ee 100644
--- a/app/assets/javascripts/single_page/dynamic_table.js.erb
+++ b/app/assets/javascripts/single_page/dynamic_table.js.erb
@@ -230,6 +230,8 @@ const handleSelect = (e) => {
sampleLinksTitles.map((x) => `"${x}"`).join(", ") +
"\nYou need to manually input them."
);
+ }).catch((error) =>{
+ alert(`Paste action aborted:\n\n${error}\n\nNote: Some browsers require to click 'paste' to paste the information in the table.`);
});
} catch (error) {
diff --git a/app/assets/javascripts/single_page/index.js.erb b/app/assets/javascripts/single_page/index.js.erb
index f9beb902db..85994ee285 100644
--- a/app/assets/javascripts/single_page/index.js.erb
+++ b/app/assets/javascripts/single_page/index.js.erb
@@ -282,6 +282,25 @@ async function batchUpdateSample(sampleTypes) {
}
}
+async function handleUploadSubmit(formData){
+ $j.ajax({
+ type: 'POST',
+ url: "<%= upload_samples_single_pages_path %>",
+ data: formData,
+ dataType: 'html',
+ processData: false,
+ contentType: false,
+ enctype: 'multipart/form-data',
+ success: function(response){
+ $j('#upload-excel-modal').modal({backdrop: 'static', keyboard: false}, 'show').focus();
+ $j('#upload-excel').html(response);
+ },
+ error: function(err){
+ location.reload(); // Page needs reloading for the notice message to appear
+ }
+ });
+}
+
function isMobile() {
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
}
diff --git a/app/assets/javascripts/zenodo_form.js b/app/assets/javascripts/zenodo_form.js
index 8f003bee94..30c43b5722 100644
--- a/app/assets/javascripts/zenodo_form.js
+++ b/app/assets/javascripts/zenodo_form.js
@@ -1,21 +1,6 @@
var zenodoExport = {
creatorList: [],
- setLicenseUrl: function () {
- var element = $j('#license-select option:selected');
- var link = $j('#license-url');
- var block = link.parents('.license-url-block');
-
- if(element.data('url') == '') {
- block.hide();
- } else {
- block.show();
- }
-
- link.attr('href', element.data('url'));
- link.html(element.data('url'));
- },
-
enableSection: function (sectionElement) {
sectionElement.show().children(":input").prop("disabled", false);
},
diff --git a/app/assets/stylesheets/linked_custom_metadata.css b/app/assets/stylesheets/linked_custom_metadata.css
index 265f876954..596f1cb2f4 100644
--- a/app/assets/stylesheets/linked_custom_metadata.css
+++ b/app/assets/stylesheets/linked_custom_metadata.css
@@ -28,4 +28,30 @@
padding: 10px 15px 10px 15px;
border-radius: 5px;
-}
\ No newline at end of file
+}
+
+.multi_linked_custom_metdata {
+ background-color: rgb(246, 246, 246);
+ padding: 10px 15px 10px 15px;
+ border-radius: 5px;
+ margin-bottom: 15px;
+}
+
+.linked_custom_metdata_display .panel-default .panel-heading {
+ font-weight: bold;
+ border: none;
+ background-color: #ffffff;
+ padding: 0px 0px;
+}
+
+
+.linked_custom_metdata_display .panel {
+ border: none;
+ box-shadow: none;
+ margin-bottom: 0px;
+}
+
+.linked_custom_metdata_display .panel-body {
+ padding: 0px 0px;
+ border-radius: 5px;
+}
diff --git a/app/assets/stylesheets/publishing.scss b/app/assets/stylesheets/publishing.scss
index 1de7aec917..3a9e3bed42 100644
--- a/app/assets/stylesheets/publishing.scss
+++ b/app/assets/stylesheets/publishing.scss
@@ -17,14 +17,6 @@ ul.publishing_options li.secondary {
}
-.published {
- color: limegreen;
-}
-
-span.published {
- color: green;
-}
-
span.approve {
color: limegreen;
font-weight: bolder;
@@ -64,13 +56,12 @@ ul.item_for_decision {
.publishing_options {
padding: 0.5em 1em;
- &.publishable {
- background-color: #fafaff;
- border-left-color: $btn-success-bg;
+ &.not-manageable {
+ border-left-color: $btn-warning-bg;
}
- &.not-publishable {
- border-left-color: $btn-warning-bg;
+ &.not-visible {
+ border-left-color: $btn-danger-bg;
}
&.already-published {
@@ -78,18 +69,6 @@ ul.item_for_decision {
}
}
-.publish-colour {
- color: $btn-success-bg;
-}
-
-.publish-checkbox {
- background-color: $btn-success-bg;
- color: $btn-success-color;
- padding: 0px 10px;
- border-radius: 5px;
- display: inline-block;
-}
-
ul.decided_item {
padding-left: 1em;
}
@@ -108,3 +87,43 @@ ul.decided_item li.type_and_title {
padding: 0.5em 15px;
margin: 0.3em 0em;
}
+
+.batch-selection-buttons {
+ margin-bottom: 1em;
+ display: flex;
+ gap: 1em;
+}
+
+.batch-selection-asset-row {
+ display: flex;
+ gap: 1em;
+ align-items: center;
+ .visibility_icon {
+ margin: 0;
+ }
+}
+
+.batch-selection-permission-list,
+.batch-selection-managed-by-list,
+.batch-selection-children {
+ margin-left: 3em;
+}
+
+.batch-selection-check-btn {
+ input {
+ margin: 0;
+ vertical-align: middle;
+ }
+}
+
+.batch-selection-collapse-toggle {
+ cursor: pointer;
+
+ .glyphicon-menu-down { display: none; };
+ .glyphicon-menu-right { display: inline; };
+
+ &.open {
+ .glyphicon-menu-down { display: inline; };
+ .glyphicon-menu-right { display: none; };
+ }
+}
diff --git a/app/assets/stylesheets/sharing.scss b/app/assets/stylesheets/sharing.scss
index d396101a0c..6f56e31c5f 100644
--- a/app/assets/stylesheets/sharing.scss
+++ b/app/assets/stylesheets/sharing.scss
@@ -210,17 +210,3 @@
padding-left: 16px;
}
}
-
-.parent-btn-checkbox {
- padding: 1px 6px 0px 6px;
- border-radius: 5px;
- display: inline-block;
- height: 25px;
-}
-.parent-btn-dropdown {
- padding: 2px 6px 10px 0px;
- border-radius: 5px;
- display: inline-block;
- height: 25px;
-}
-
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
index 218c6a81b4..77d2b76e3d 100644
--- a/app/controllers/admin_controller.rb
+++ b/app/controllers/admin_controller.rb
@@ -163,6 +163,7 @@ def update_features_enabled
Seek::Config.life_monitor_url = params[:life_monitor_url]&.strip&.chomp('/')
Seek::Config.life_monitor_client_id = params[:life_monitor_client_id]&.strip
Seek::Config.life_monitor_client_secret = params[:life_monitor_client_secret]&.strip
+ Seek::Config.life_monitor_ui_url = params[:life_monitor_ui_url]&.strip&.chomp('/')
Seek::Config.bio_tools_enabled = string_to_boolean(params[:bio_tools_enabled])
@@ -331,8 +332,8 @@ def update_settings
Seek::Config.default_license = params[:default_license]
Seek::Config.metadata_license = params[:metadata_license]
- Seek::Config.recommended_data_licenses = params[:recommended_data_licenses]
- Seek::Config.recommended_software_licenses = params[:recommended_software_licenses]
+ Seek::Config.recommended_data_licenses = params[:recommended_data_licenses]&.compact_blank
+ Seek::Config.recommended_software_licenses = params[:recommended_software_licenses]&.compact_blank
update_flag = (pubmed_email == '' || pubmed_email_valid) && (crossref_email == '' || crossref_email_valid)
update_redirect_to update_flag, 'settings'
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 734f468bac..37c31e87a6 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -597,33 +597,26 @@ def relationify_collection(collection)
end
def determine_custom_metadata_keys
-
- root_key = controller_name.singularize.to_sym
- return [] unless params[root_key][:custom_metadata_attributes].present?
- attribute_params = params[root_key][:custom_metadata_attributes]
- recursive_determine_custom_metadata_keys(attribute_params)
-
+ keys = []
+ type_id = params.dig(controller_name.singularize.to_sym, :custom_metadata_attributes, :custom_metadata_type_id)
+ if type_id.present?
+ metadata_type = CustomMetadataType.find(type_id)
+ keys = [:custom_metadata_type_id, :id, data: recursive_determine_custom_metadata_keys(metadata_type)]
+ end
+ keys
end
- # todo currently 2-level nested attributes are tested, we would like to test if it also works with more level nested attributes
- def recursive_determine_custom_metadata_keys(attribute_params)
+ def recursive_determine_custom_metadata_keys(metadata_type)
keys = []
- if attribute_params && attribute_params[:custom_metadata_type_id].present?
- metadata_type = CustomMetadataType.find(attribute_params[:custom_metadata_type_id])
- if metadata_type
- keys = [:custom_metadata_type_id,:id,:custom_metadata_attribute_id]
- cma= []
- metadata_type.custom_metadata_attributes.each do |attr|
- if attr.sample_attribute_type.controlled_vocab? || attr.sample_attribute_type.seek_sample_multi?
- cma << {attr.title=>[]}
- cma << attr.title.to_s
- elsif attr.linked_custom_metadata?
- cma << { attr.title => recursive_determine_custom_metadata_keys(attribute_params[:data][attr.title.to_sym])}
- else
- cma << attr.title.to_s
- end
- end
- keys = keys + [{data:cma}]
+ metadata_type.custom_metadata_attributes.each do |attr|
+ key = attr.title.to_sym
+ if attr.sample_attribute_type.controlled_vocab? || attr.sample_attribute_type.seek_sample_multi? || attr.sample_attribute_type.seek_sample?
+ keys << key
+ keys << { key => [] }
+ elsif attr.linked_custom_metadata? || attr.linked_custom_metadata_multi?
+ keys << { key => recursive_determine_custom_metadata_keys(attr.linked_custom_metadata_type) }
+ else
+ keys << key
end
end
keys
diff --git a/app/controllers/assays_controller.rb b/app/controllers/assays_controller.rb
index 48c13e0dd1..796642c82d 100644
--- a/app/controllers/assays_controller.rb
+++ b/app/controllers/assays_controller.rb
@@ -6,6 +6,7 @@ class AssaysController < ApplicationController
before_action :assays_enabled?
before_action :find_assets, :only=>[:index]
before_action :find_and_authorize_requested_item, :only=>[:edit, :update, :destroy, :manage, :manage_update, :show, :new_object_based_on_existing_one]
+ before_action :delete_linked_sample_types, only: [:destroy]
#project_membership_required_appended is an alias to project_membership_required, but is necessary to include the actions
#defined in the application controller
@@ -18,7 +19,7 @@ class AssaysController < ApplicationController
api_actions :index, :show, :create, :update, :destroy
def new_object_based_on_existing_one
- @existing_assay = Assay.find(params[:id])
+ @existing_assay = Assay.find(params[:id])
@assay = @existing_assay.clone_with_associations
if @existing_assay.can_view?
@@ -62,9 +63,7 @@ def new_object_based_on_existing_one
flash[:error]="You do not have the necessary permissions to copy this #{t('assays.assay')}"
redirect_to @existing_assay
end
-
-
- end
+ end
def new
@assay=setup_new_asset
@@ -112,6 +111,13 @@ def create
end
end
+
+ def delete_linked_sample_types
+ return unless is_single_page_assay?
+
+ @assay.sample_type.destroy
+ end
+
def update
update_assay_organisms @assay, params
update_assay_human_diseases @assay, params
@@ -177,4 +183,10 @@ def assay_params
assay_params[:model_ids].select! { |id| Model.find_by_id(id).try(:can_view?) } if assay_params.key?(:model_ids)
end
end
+
+ def is_single_page_assay?
+ return false unless params.key?(:return_to)
+
+ params[:return_to].start_with? '/single_pages/'
+ end
end
diff --git a/app/controllers/samples_controller.rb b/app/controllers/samples_controller.rb
index 6e72ae8e23..91d53f5645 100644
--- a/app/controllers/samples_controller.rb
+++ b/app/controllers/samples_controller.rb
@@ -75,6 +75,11 @@ def show
def edit
@sample = Sample.find(params[:id])
+ if !@sample.originating_data_file.nil? && @sample.edit_count.zero?
+ flash.now[:error] = 'Warning: This sample was extracted from a datafile.
+ If you edit the sample, it will no longer correspond to the original source data.
+ Unless you cancel, a label will be added to the sample\'s source field to indicate it is no longer valid.'.html_safe
+ end
respond_with(@sample)
end
@@ -201,7 +206,7 @@ def typeahead
query = params[:q] || ''
sample_type = SampleType.find(params[:linked_sample_type_id])
results = sample_type.samples.where("LOWER(title) like :query",
- query: "%#{query.downcase}%").limit(params[:limit] || 100)
+ query: "%#{query.downcase}%").limit(params[:limit] || 100).authorized_for(:view)
items = results.map do |sa|
{ id: sa.id,
text: sa.title }
@@ -266,7 +271,7 @@ def sample_params(sample_type = nil, parameters = params)
if sample_type
sample_type.sample_attributes.each do |attr|
- if attr.sample_attribute_type.controlled_vocab? || attr.sample_attribute_type.seek_sample_multi?
+ if attr.sample_attribute_type.controlled_vocab? || attr.sample_attribute_type.seek_sample_multi? || attr.sample_attribute_type.seek_sample?
sample_type_param_keys << { attr.title => [] }
sample_type_param_keys << attr.title.to_sym
else
diff --git a/app/controllers/single_pages_controller.rb b/app/controllers/single_pages_controller.rb
index 1914f403bc..591eb2600c 100644
--- a/app/controllers/single_pages_controller.rb
+++ b/app/controllers/single_pages_controller.rb
@@ -1,8 +1,11 @@
require 'isatab_converter'
+# Controller for the Single Page view
class SinglePagesController < ApplicationController
include Seek::AssetsCommon
include Seek::Sharing::SharingCommon
+ include Seek::Publishing::PublishingCommon
+ include Seek::Data::SpreadsheetExplorerRepresentation
before_action :set_up_instance_variable
before_action :project_single_page_enabled?
@@ -14,9 +17,7 @@ class SinglePagesController < ApplicationController
def show
@project = Project.find(params[:id])
@folders = project_folders
- respond_to do |format|
- format.html
- end
+ respond_to(&:html)
end
def index; end
@@ -61,21 +62,20 @@ def export_isa
end
def download_samples_excel
-
sample_ids, sample_type_id, study_id, assay_id = Rails.cache.read(params[:uuid]).values_at(:sample_ids, :sample_type_id,
- :study_id, :assay_id)
+ :study_id, :assay_id)
@study = Study.find(study_id)
@assay = Assay.find(assay_id) unless assay_id.nil?
@project = @study.projects.first
- @samples = Sample.where(id: sample_ids)&.authorized_for(:view).sort_by(&:id)
+ @samples = Sample.where(id: sample_ids)&.authorized_for(:view)&.sort_by(&:id)
- raise "Nothing to export to Excel." if @samples.nil? || @samples == [] || sample_type_id.nil?
+ raise 'Nothing to export to Excel.' if @samples.nil? || @samples == [] || sample_type_id.nil?
@sample_type = SampleType.find(sample_type_id)
sample_attributes = @sample_type.sample_attributes.map do |sa|
- obj = if (sa.sample_controlled_vocab_id.nil?)
+ obj = if sa.sample_controlled_vocab_id.nil?
{ sa_cv_title: sa.title, sa_cv_id: nil }
else
{ sa_cv_title: sa.title, sa_cv_id: sa.sample_controlled_vocab_id }
@@ -83,17 +83,20 @@ def download_samples_excel
obj.merge({ required: sa.required })
end
- @sa_cv_terms = [{ "name" => "id", "has_cv" => false, "data" => nil, "allows_custom_input" => nil, "required" => nil },
- { "name" => "uuid", "has_cv" => false, "data" => nil, "allows_custom_input" => nil, "required" => nil }]
+ @sa_cv_terms = [{ 'name' => 'id', 'has_cv' => false, 'data' => nil, 'allows_custom_input' => nil, 'required' => nil },
+ { 'name' => 'uuid', 'has_cv' => false, 'data' => nil, 'allows_custom_input' => nil,
+ 'required' => nil }]
sample_attributes.map do |sa|
- if sa[:sa_cv_id].nil?
- @sa_cv_terms.push({ "name" => sa[:sa_cv_title], "has_cv" => false, "data" => nil, "allows_custom_input" => nil, "required" => sa[:required] })
- else
- allows_custom_input = SampleControlledVocab.find(sa[:sa_cv_id])&.custom_input
- sa_terms = SampleControlledVocabTerm.where(sample_controlled_vocab_id: sa[:sa_cv_id]).map(&:label)
- @sa_cv_terms.push({ "name" => sa[:sa_cv_title], "has_cv" => true, "data" => sa_terms, "allows_custom_input" => allows_custom_input, "required" => sa[:required] })
- end
+ if sa[:sa_cv_id].nil?
+ @sa_cv_terms.push({ 'name' => sa[:sa_cv_title], 'has_cv' => false, 'data' => nil,
+ 'allows_custom_input' => nil, 'required' => sa[:required] })
+ else
+ allows_custom_input = SampleControlledVocab.find(sa[:sa_cv_id])&.custom_input
+ sa_terms = SampleControlledVocabTerm.where(sample_controlled_vocab_id: sa[:sa_cv_id]).map(&:label)
+ @sa_cv_terms.push({ 'name' => sa[:sa_cv_title], 'has_cv' => true, 'data' => sa_terms,
+ 'allows_custom_input' => allows_custom_input, 'required' => sa[:required] })
+ end
end
@template = Template.find(@sample_type.template_id)
@@ -102,13 +105,15 @@ def download_samples_excel
flash[:error] = e.message
respond_to do |format|
format.html { redirect_to single_page_path(@project.id) }
- format.json { render json: { parameters: { sample_ids: sample_ids, sample_type_id: sample_type_id, study_id: study_id } } }
+ format.json do
+ render json: { parameters: { sample_ids:, sample_type_id:, study_id: } }
+ end
end
end
def export_to_excel
cache_uuid = UUID.new.generate
- id_label = "#{Seek::Config::instance_name} id"
+ id_label = "#{Seek::Config.instance_name} id"
sample_ids = JSON.parse(params[:sample_data]).map { |sample| sample[id_label] unless sample[id_label] == '#HIDDEN' }
sample_type_id = JSON.parse(params[:sample_type_id])
study_id = JSON.parse(params[:study_id])
@@ -122,8 +127,232 @@ def export_to_excel
end
end
+ def upload_samples
+ uploaded_file = params[:file]
+ project_id = params[:project_id]
+ @project = Project.find(project_id)
+
+ # Check file type if is xls or xlsx
+ case uploaded_file.content_type
+ when 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ spreadsheet_xml = spreadsheet_to_xml(uploaded_file.path, Seek::Config.jvm_memory_allocation)
+ wb = parse_spreadsheet_xml(spreadsheet_xml)
+ metadata_sheet = wb.sheet('Metadata')
+ samples_sheet = wb.sheet('Samples')
+ else
+ raise "Please upload a valid spreadsheet file with extension '.xlsx'"
+ end
+
+ sample_type_id_ui = params[:sample_type_id].to_i
+
+ unless valid_workbook?(wb)
+ raise 'Invalid workbook! Cannot process this spreadsheet. Consider first exporting the table as a spreadsheet for the proper format.'
+ end
+
+ # Extract Samples metadata from spreadsheet
+ study_id = metadata_sheet.cell(2, 2).value.to_i
+ @study = Study.find(study_id)
+ sample_type_id = metadata_sheet.cell(5, 2).value.to_i
+ @sample_type = SampleType.find(sample_type_id)
+ is_assay = @sample_type.assays.any?
+ @assay = @sample_type.assays.first
+
+ # Sample Type validation rules
+ unless sample_type_id_ui == @sample_type&.id
+ raise "Sample Type #{@sample_type&.id} from spreadsheet doesn't match Sample Type #{sample_type_id_ui} from the table. Please upload in the correct table."
+ end
+ unless @study.sample_types.include?(@sample_type) || is_assay
+ raise "Sample Type '#{@sample_type.id}' doesn't belong to Study #{@study.id}. Sample Upload aborted."
+ end
+ unless (@assay&.sample_type == @sample_type) || !is_assay
+ raise "Sample Type '#{@sample_type.id}' doesn't belong to Assay #{@assay.id}. Sample Upload aborted."
+ end
+
+ @multiple_input_fields = @sample_type.sample_attributes.map do |sa_attr|
+ sa_attr.title if sa_attr.sample_attribute_type.base_type == 'SeekSampleMulti'
+ end
+
+ sample_fields, samples_data = get_spreadsheet_data(samples_sheet)
+
+ # Compare Excel header row to Sample Type Sample Attributes
+ # Should raise an error if they don't match
+ sample_type_attributes = %w[id uuid].concat(@sample_type.sample_attributes.map(&:title))
+ has_unmapped_sample_attributes = sample_type_attributes.map { |sa| sample_fields.include?(sa) }.include?(false)
+ if has_unmapped_sample_attributes
+ raise "The Sample Attributes from the excel sheet don't match those of the Sample Type in the database. Sample upload was aborted!"
+ end
+
+ # Construct Samples objects from Excel data
+ excel_samples = generate_excel_samples(samples_data, sample_fields)
+
+ existing_excel_samples = excel_samples.map { |sample| sample unless sample['id'].nil? }.compact
+ new_excel_samples = excel_samples.map { |sample| sample if sample['id'].nil? }.compact
+
+ # Retrieve all samples of the Sample Type, also the unauthorized ones
+ @db_samples = sample_type_samples(@sample_type)
+ # Retrieve the Sample Types samples wich are authorized for editing
+ @authorized_db_samples = sample_type_samples(@sample_type, :edit)
+
+ # Determine whether samples have been modified or not,
+ # and checking whether the user is permitted to edit them
+ @unauthorized_samples, @update_samples = separate_unauthorized_samples(existing_excel_samples, @db_samples,
+ @authorized_db_samples)
+
+ # Determine if the new samples are no duplicates of existing ones,
+ # based on the attribute values
+ @possible_duplicates, @new_samples = separate_possible_duplicates(new_excel_samples, @db_samples)
+
+ upload_data = { study: @study,
+ assay: @assay,
+ sampleType: @sample_type,
+ excel_samples:,
+ existingExcelSamples: existing_excel_samples,
+ newExcelSamples: new_excel_samples,
+ updateSamples: @update_samples,
+ newSamples: @new_samples,
+ possibleDuplicates: @possible_duplicates,
+ dbSamples: @db_samples,
+ authorized_db_samples: @authorized_db_samples,
+ unauthorized_samples: @unauthorized_samples }
+
+ respond_to do |format|
+ format.json { render json: { uploadData: upload_data } }
+ format.html { render 'single_pages/sample_upload_content', { layout: false } }
+ end
+ rescue StandardError => e
+ flash[:error] = e.message
+ respond_to do |format|
+ format.html { redirect_to single_page_path(@project), status: :bad_request }
+ format.json { render json: { error: e }, status: :bad_request }
+ end
+ end
+
private
+ def get_spreadsheet_data(samples_sheet)
+ sample_fields = samples_sheet.row(1).actual_cells.map { |field| field&.value&.sub(' *', '') }.compact
+ samples_data = (2..samples_sheet.actual_rows.size).map do |i|
+ sample_cells = samples_sheet.row(i).cells
+ next if sample_cells.all? { |cell| (cell&.value == '' || cell&.value.nil?) }
+
+ sample_cells.map do |cell|
+ cell&.value
+ end.drop(1)
+ end.compact
+
+ [sample_fields, samples_data]
+ end
+
+ def generate_excel_samples(samples_data, sample_fields)
+ samples_data.map do |excel_sample|
+ obj = {}
+ (0..sample_fields.size - 1).map do |i|
+ if @multiple_input_fields.include?(sample_fields[i])
+ parsed_excel_input_samples = JSON.parse(excel_sample[i].gsub(/"=>/x, '":')).map do |subsample|
+ # Uploader should at least have viewing permissions for the inputs he's using
+ unless Sample.find(subsample['id'])&.authorized_for_view?
+ raise "Unauthorized Sample was detected in spreadsheet: #{subsample.inspect}"
+ end
+
+ subsample
+ end
+ obj.merge!(sample_fields[i] => parsed_excel_input_samples)
+ elsif sample_fields[i] == 'id'
+ if excel_sample[i] == ''
+ obj.merge!(sample_fields[i] => nil)
+ else
+ obj.merge!(sample_fields[i] => excel_sample[i]&.to_i)
+ end
+ else
+ obj.merge!(sample_fields[i] => excel_sample[i])
+ end
+ end
+ obj
+ end
+ end
+
+ def sample_type_samples(sample_type, authorization_method = nil)
+ if authorization_method
+ sample_type.samples&.authorized_for(authorization_method)&.map do |sample|
+ attributes = JSON.parse(sample[:json_metadata])
+ { 'id' => sample.id,
+ 'uuid' => sample.uuid }.merge(attributes)
+ end
+ else
+ sample_type.samples&.map do |sample|
+ attributes = JSON.parse(sample[:json_metadata])
+ { 'id' => sample.id,
+ 'uuid' => sample.uuid }.merge(attributes)
+ end
+ end
+ end
+
+ def separate_unauthorized_samples(existing_excel_samples, db_samples, authorized_db_samples)
+ update_samples = []
+ unauthorized_samples = []
+ existing_excel_samples.map do |ees|
+ db_sample = db_samples.select { |s| s['id'] == ees['id'] }.first
+
+ # An exception is raised if the ID of an existing Sample cannot be found in the DB
+ raise "Sample with id '#{ees['id']}' does not exist in the database. Sample upload was aborted!" if db_sample.nil?
+
+ is_authorized_for_update = authorized_db_samples.select { |s| s['id'] == ees['id'] }.any?
+
+ is_changed = false
+
+ db_sample.map do |k, v|
+ unless ees[k] == v
+ is_changed = true
+ break
+ end
+ end
+
+ if is_changed
+ if is_authorized_for_update
+ update_samples.append(ees)
+ else
+ unauthorized_samples.append(ees)
+ end
+ end
+ end
+ [unauthorized_samples, update_samples]
+ end
+
+ def separate_possible_duplicates(new_excel_samples, db_samples)
+ possible_duplicates = []
+ new_samples = []
+ new_excel_samples.map do |nes|
+ is_duplicate = true
+
+ db_samples.map do |dbs|
+ dbs.map do |k, v|
+ unless %w[id uuid].include?(k)
+ is_duplicate = (nes[k] == v)
+ break unless is_duplicate
+ end
+ end
+
+ if is_duplicate
+ possible_duplicates.append(nes.merge({ 'duplicate' => dbs }))
+ break
+ end
+ end
+
+ if db_samples.none?
+ new_samples.append(nes)
+ else
+ new_samples.append(nes) unless is_duplicate
+ end
+ end
+ [possible_duplicates, new_samples]
+ end
+
+ def valid_workbook?(workbook)
+ !((workbook.sheet_names.map do |sheet|
+ %w[Metadata Samples cv_ontology].include? sheet
+ end.include? false) && (workbook.sheets.size != 3))
+ end
+
def set_up_instance_variable
@single_page = true
end
@@ -134,8 +363,8 @@ def find_authorized_investigation
end
def check_user_logged_in
- unless current_user
- render json: { status: :unprocessable_entity, error: 'You must be logged in to access batch sharing permission.' }
- end
+ return if current_user
+
+ render json: { status: :unprocessable_entity, error: 'You must be logged in to access batch sharing permission.' }
end
end
diff --git a/app/controllers/snapshots_controller.rb b/app/controllers/snapshots_controller.rb
index 7f1d9fb36a..ebeb52f528 100644
--- a/app/controllers/snapshots_controller.rb
+++ b/app/controllers/snapshots_controller.rb
@@ -15,8 +15,13 @@ class SnapshotsController < ApplicationController
def create
@snapshot = @resource.create_snapshot
- flash[:notice] = "Snapshot created"
- redirect_to polymorphic_path([@resource, @snapshot])
+ if @snapshot
+ flash[:notice] = "Snapshot created"
+ redirect_to polymorphic_path([@resource, @snapshot])
+ else
+ flash[:error] = @resource.errors.full_messages.join(', ')
+ redirect_to polymorphic_path(@resource)
+ end
end
def show
diff --git a/app/controllers/studies_controller.rb b/app/controllers/studies_controller.rb
index 2aed0d36a1..4386e966b9 100644
--- a/app/controllers/studies_controller.rb
+++ b/app/controllers/studies_controller.rb
@@ -6,6 +6,7 @@ class StudiesController < ApplicationController
before_action :studies_enabled?
before_action :find_assets, only: [:index]
before_action :find_and_authorize_requested_item, only: %i[edit update destroy manage manage_update show new_object_based_on_existing_one]
+ before_action :delete_linked_sample_types, only: [:destroy]
# project_membership_required_appended is an alias to project_membership_required, but is necesary to include the actions
# defined in the application controller
@@ -69,11 +70,10 @@ def update
format.html { redirect_to(@study) }
end
else
- @study.attributes = study_params
+ @study.assign_attributes(study_params)
update_sharing_policies @study
update_annotations(params[:tag_list], @study)
update_relationships(@study, params)
- update_linked_custom_metadatas @study
respond_to do |format|
if @study.save
@@ -88,6 +88,16 @@ def update
end
end
+ def delete_linked_sample_types
+ return unless is_single_page_study?
+
+ # The study sample types must be destroyed in reversed order
+ # otherwise the first sample type won't be removed becaused it is linked from the second
+ study_st_ids = @study.sample_types.map(&:id).sort { |a, b| b <=> a }
+ SampleType.destroy(study_st_ids)
+ end
+
+
def show
@study = Study.find(params[:id])
@@ -103,7 +113,6 @@ def create
update_sharing_policies @study
update_annotations(params[:tag_list], @study)
update_relationships(@study, params)
- update_linked_custom_metadatas @study
### TO DO: what about validation of person responsible? is it already included (for json?)
if @study.save
@@ -201,7 +210,7 @@ def batch_create
study_params = {
title: params[:studies][:title][index],
description: params[:studies][:description][index],
- investigation_id: params[:study][:investigation_id],
+ investigation_id: params[:study][:investigation_id],
custom_metadata: CustomMetadata.new(
custom_metadata_type: metadata_types,
data: metadata
@@ -351,3 +360,9 @@ def study_params
{ custom_metadata_attributes: determine_custom_metadata_keys })
end
end
+
+def is_single_page_study?
+ return false unless params.key?(:return_to)
+
+ params[:return_to].start_with? '/single_pages/'
+end
diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb
index 7e225e2201..9143eef2f3 100644
--- a/app/controllers/templates_controller.rb
+++ b/app/controllers/templates_controller.rb
@@ -91,7 +91,7 @@ def task_status
def populate_template
uploaded_file = params[:template_json_file]
- dir = Rails.root.join('config', 'default_data', 'source_types')
+ dir = Seek::Config.append_filestore_path('source_types')
if Dir.exist?(dir)
`rm #{dir}/*`
@@ -177,11 +177,11 @@ def set_status
end
def lockfile
- Rails.root.join('tmp', 'populate_templates.lock')
+ Rails.root.join(Seek::Config.temporary_filestore_path, 'populate_templates.lock')
end
def resultfile
- Rails.root.join('tmp', 'populate_templates.result')
+ Rails.root.join(Seek::Config.temporary_filestore_path, 'populate_templates.result')
end
def running!
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
index 3b8261316c..ab67f6ea1b 100644
--- a/app/helpers/admin_helper.rb
+++ b/app/helpers/admin_helper.rb
@@ -94,11 +94,11 @@ def git_link_tag
end
end
- def admin_setting_block(title, description)
+ def admin_setting_block(title, description = nil)
content_tag(:div, class: 'form-group') do
- content_tag(:label, title) +
- (description ? content_tag(:p, description.html_safe, class: 'help-block') : ''.html_safe) +
- yield
+ concat content_tag(:label, title)
+ concat content_tag(:p, description.html_safe, class: 'help-block') if description
+ concat yield
end
end
end
diff --git a/app/helpers/assets_helper.rb b/app/helpers/assets_helper.rb
index b3b74a9228..05c4d64ee1 100644
--- a/app/helpers/assets_helper.rb
+++ b/app/helpers/assets_helper.rb
@@ -94,18 +94,6 @@ def publishing_item_param(item)
"publish[#{item.class.name}][#{item.id}]"
end
- def sharing_item_param(item)
- if item.try(:is_isa?)
- "share_isa[#{item.class.name}][#{item.id}]"
- elsif (item.respond_to? (:investigations)) && (!item.investigations.any?)
- "share_not_isa[#{item.class.name}][#{item.id}]"
- elsif !item.respond_to? (:investigations)
- "share_not_isa[#{item.class.name}][#{item.id}]"
- else
- "share_isa[#{item.class.name}][#{item.id}]"
- end
- end
-
def include_downloadable_item?(items)
has_downloadable_item = false
items.each do |item|
@@ -346,4 +334,10 @@ def controlled_vocab_annotation_items(controlled_vocab_terms)
end.join(', ').html_safe
end
+ def batch_selection_collapse_toggle
+ content_tag(:span, class: 'batch-selection-collapse-toggle open') do
+ concat content_tag(:span, '', class: 'glyphicon glyphicon-menu-down', 'aria-hidden' => 'true')
+ concat content_tag(:span, '', class: 'glyphicon glyphicon-menu-right', 'aria-hidden' => 'true')
+ end
+ end
end
diff --git a/app/helpers/bootstrap_helper.rb b/app/helpers/bootstrap_helper.rb
index 1c56e72242..d50ba165b9 100644
--- a/app/helpers/bootstrap_helper.rb
+++ b/app/helpers/bootstrap_helper.rb
@@ -127,20 +127,23 @@ def objects_input(element_name, existing_objects = [], options = {}, value_metho
options['data-allow-new-items'] = options.delete(:allow_new) if options[:allow_new]
options['data-placeholder'] = options.delete(:placeholder) if options[:placeholder]
options[:include_blank] = ''
- options[:multiple] = true
- options[:name] = "#{element_name}[]" unless options.key?(:name)
+ options[:multiple] = true unless options.key?(:multiple)
+ options[:name] = "#{element_name}#{options[:multiple] ? '[]': ''}" unless options.key?(:name)
options.merge!(typeahead_options(options.delete(:typeahead))) if options[:typeahead]
- select_options = options_from_collection_for_select(
- existing_objects,
- value_method, text_method,
- existing_objects.collect { |obj| obj.send(value_method) }
- )
+ select_options = options.delete(:select_options) ||
+ options_from_collection_for_select(
+ existing_objects,
+ value_method, text_method,
+ existing_objects.collect { |obj| obj.send(value_method) }
+ )
- hidden_field_tag(element_name, '', name: options[:name]) +
- select_tag(element_name,
- select_options,
- options)
+ tag = select_tag(element_name, select_options, options)
+ if options[:multiple]
+ hidden_field_tag(element_name, '', name: options[:name]) + tag
+ else
+ tag
+ end
end
def modal(options = {}, &block)
diff --git a/app/helpers/custom_metadata_helper.rb b/app/helpers/custom_metadata_helper.rb
index 1801554c4c..57267f2ba2 100644
--- a/app/helpers/custom_metadata_helper.rb
+++ b/app/helpers/custom_metadata_helper.rb
@@ -5,15 +5,15 @@ def custom_metadata_form_field_for_attribute(attribute, resource)
element_class = "custom_metadata_attribute_#{attribute.sample_attribute_type.base_type.downcase}"
element_name = "#{resource.class.name.underscore}[custom_metadata_attributes][data][#{attribute.title}]"
- if attribute.linked_custom_metadata?
+ if attribute.linked_custom_metadata? || attribute.linked_custom_metadata_multi?
content_tag(:span, class: 'linked_custom_metdata') do
folding_panel(attribute.label, false, id:attribute.title) do
- attribute_form_element(attribute, resource.custom_metadata, element_name, element_class)
+ attribute_form_element(attribute, resource.custom_metadata.get_attribute_value(attribute.title), element_name, element_class)
end
end
else
content_tag(:label,attribute.label, class: attribute.required? ? 'required' : '') +
- attribute_form_element(attribute, resource.custom_metadata, element_name, element_class)
+ attribute_form_element(attribute, resource.custom_metadata.get_attribute_value(attribute.title), element_name, element_class)
end
end
@@ -24,4 +24,22 @@ def custom_metadata_attribute_description(description)
html.html_safe
end
-end
\ No newline at end of file
+ def render_custom_metadata_value(attribute, resource)
+
+ if resource.custom_metadata.data[attribute.title].blank?
+ return '' # Return an empty string if the custom metadata is blank.
+ end
+
+ content_tag(:div, class: 'custom_metadata') do
+ if attribute.linked_custom_metadata? || attribute.linked_custom_metadata_multi?
+ content_tag(:span, class: 'linked_custom_metdata_display') do
+ folding_panel(attribute.label, true, id: attribute.title) do
+ display_attribute(resource.custom_metadata, attribute, link: true)
+ end
+ end
+ else
+ label_tag("#{attribute.label}:") + display_attribute(resource.custom_metadata, attribute, link: true)
+ end
+ end
+ end
+end
diff --git a/app/helpers/license_helper.rb b/app/helpers/license_helper.rb
index db4f841fb0..6187ecbb43 100644
--- a/app/helpers/license_helper.rb
+++ b/app/helpers/license_helper.rb
@@ -3,15 +3,23 @@
module LicenseHelper
def license_select(name, selected = nil, opts = {})
- select_tag(name, options_for_select(license_options(opts), selected), opts)
- end
+ opts[:data] ||= {}
+ opts[:data]['seek-license-select'] ||= 'true'
+ opts[:multiple] = false
+
+ recommended = opts.delete(:recommended)
+ source = opts.delete(:source) || Seek::License.combined
+ if recommended
+ opts[:select_options] = grouped_options_for_select(grouped_license_options(source.values, recommended), selected)
+ else
+ opts[:select_options] = options_for_select(license_options(source.values), selected)
+ end
- def grouped_license_select(name, selected = nil, opts = {})
- select_tag(name, grouped_options_for_select(grouped_license_options(opts), selected), opts)
+ objects_input(name, [], opts)
end
- def describe_license(id, source = nil)
- license = Seek::License.find(id, source)
+ def describe_license(id)
+ license = Seek::License.find(id)
content = license_description_content(license)
if !license || license.is_null_license?
@@ -67,50 +75,34 @@ def license_description_content(license)
end
end
- def license_values(opts = {})
- opts.delete(:source) || Seek::License.open_definition[:all]
- end
-
- def license_options(opts = {})
- license_values(opts).map { |value| [value['title'], value['id'], { 'data-url' => value['url'] }] }
- end
-
- def grouped_license_options(opts = {})
- grouped_licenses = sort_grouped_licenses(group_licenses(opts))
-
- grouped_licenses.each do |g, licenses|
- licenses.map! { |value| [value['title'], value['id'], { 'data-url' => value['url'] }] }
- end
-
- grouped_licenses
- end
-
- def sort_grouped_licenses(licenses)
- s = licenses.sort_by do |pair|
- case pair[0]
- when 'recommended'
- 0
-# when 'Generic'
-# 2
+ def license_options(licenses)
+ licenses.map do |value|
+ [value['title'], value['id'], { 'data-url' => value['url'] }]
+ end.sort_by do |value|
+ if value[1] == Seek::License::NULL_LICENSE # Put null license first
+ '-'
else
- 3
+ value[0] # Otherwise sort by title
end
end
- s.each do |pair|
- pair[0] = "#{t('licenses.' + pair[0])}"
- end
- s
end
- def group_licenses(opts)
- recommended = opts.delete(:recommended)
- license_values(opts).group_by do |l|
+ def grouped_license_options(licenses, recommended)
+ grouped_licenses = licenses.group_by do |l|
if recommended&.include?(l['id'])
'recommended'
else
'other'
end
- end.to_a
+ end
+
+ grouped_licenses.transform_values! do |l|
+ license_options(l)
+ end
+
+ # Transform into array to ensure recommended licenses come first
+ ['recommended', 'other'].map do |key|
+ [t("licenses.#{key}"), grouped_licenses[key] || []]
+ end
end
-
end
diff --git a/app/helpers/policy_helper.rb b/app/helpers/policy_helper.rb
index 1a70d38ff7..7c431caa93 100644
--- a/app/helpers/policy_helper.rb
+++ b/app/helpers/policy_helper.rb
@@ -159,7 +159,7 @@ def project_policy_json(project)
hash.to_json.html_safe
end
- def permission_title(permission, member_prefix: false, icon: false)
+ def permission_title(permission, member_prefix: false, icon: false, link: false)
if permission.is_a?(Permission)
type = permission.contributor_type
contributor = permission.contributor
@@ -168,18 +168,31 @@ def permission_title(permission, member_prefix: false, icon: false)
contributor = permission
end
- if type == 'Person'
+ option = { target: :_blank }
+ case type
+ when 'Person'
text = "#{contributor.first_name} #{contributor.last_name}"
- elsif type == 'WorkGroup'
- text = "#{member_prefix ? 'Members of ' : ''}#{contributor.project.title} @ #{contributor.institution.title}"
+ text = link_to(h(text), contributor, option).html_safe if link
+ when 'WorkGroup'
+ institution = contributor.institution
+ project = contributor.project
+ if link
+ text = "#{member_prefix ? 'Members of ' : ''}#{link_to(h(project.title), project, option)} @ #{link_to(h(institution.title), institution, option)}".html_safe
+ else
+ text = "#{member_prefix ? 'Members of ' : ''}#{project.title} @ #{institution.title}"
+ end
else
- text = "#{member_prefix ? 'Members of ' : ''}#{contributor.title}"
+ if link
+ text = "#{member_prefix ? 'Members of ' : ''}#{link_to(h(contributor.title), contributor, option)}".html_safe
+ else
+ text = "#{member_prefix ? 'Members of ' : ''}#{contributor.title}"
+ end
end
if icon
content_tag(:span, class: 'type-icon-wrapper') do
image_tag(asset_path(icon_filename_for_key(type.underscore)), class: 'type-icon')
- end.html_safe + " #{text}"
+ end.html_safe + " #{text}".html_safe
else
text
end
diff --git a/app/helpers/sample_types_helper.rb b/app/helpers/sample_types_helper.rb
index acc6935501..957eadc832 100644
--- a/app/helpers/sample_types_helper.rb
+++ b/app/helpers/sample_types_helper.rb
@@ -91,7 +91,7 @@ def sample_attribute_pid_help_icon
private
def displayed_sample_attribute_types
- SampleAttributeType.all.select{|x|!x.linked_custom_metadata?}
+ SampleAttributeType.all.reject{ |x|x.linked_custom_metadata? || x.linked_custom_metadata_multi? }
end
def attribute_type_link(sample_type_attribute)
diff --git a/app/helpers/samples_helper.rb b/app/helpers/samples_helper.rb
index cccf841afa..056158ceea 100644
--- a/app/helpers/samples_helper.rb
+++ b/app/helpers/samples_helper.rb
@@ -3,7 +3,7 @@ def sample_form_field_for_attribute(attribute, resource)
element_class = "sample_attribute_#{attribute.sample_attribute_type.base_type.downcase}"
element_name = "sample[data][#{attribute.title}]"
- attribute_form_element(attribute, resource, element_name, element_class)
+ attribute_form_element(attribute, resource.get_attribute_value(attribute.title), element_name, element_class)
end
def controlled_vocab_form_field(sample_controlled_vocab, element_name, values, limit = 1)
@@ -41,29 +41,25 @@ def controlled_vocab_list_form_field(sample_controlled_vocab, element_name, valu
controlled_vocab_form_field(sample_controlled_vocab, element_name, values, nil)
end
- def linked_custom_metadata_form_field(attribute,resource,element_name, element_class,depth)
- linked_cms = resource.linked_custom_metadatas.select{|cm|cm.custom_metadata_attribute==attribute}
-
- id = linked_cms.blank? ? nil : linked_cms.select{|cm| cm.custom_metadata_type.id == attribute.linked_custom_metadata_type.id}.first.id
+ def linked_custom_metadata_multi_form_field(attribute, value, element_name, element_class)
+ render partial: 'custom_metadata/fancy_linked_custom_metadata_multi_attribute_fields',
+ locals: { value: value, attribute: attribute, element_name: element_name, element_class: element_class, collapsed: false }
+ end
+ def linked_custom_metadata_form_field(attribute, value, element_name, element_class,depth)
html = ''
- html += hidden_field_tag "#{element_name}[id]",id
- html += hidden_field_tag "#{element_name}[custom_metadata_type_id]", attribute.linked_custom_metadata_type.id
- html += hidden_field_tag "#{element_name}[custom_metadata_attribute_id]", attribute.id
attribute.linked_custom_metadata_type.custom_metadata_attributes.each do |attr|
- linked_cm = linked_cms.select{|cm| cm.custom_metadata_type_id == attr.custom_metadata_type_id}.first
- linked_cm ||= CustomMetadata.new(:custom_metadata_type_id => attr.custom_metadata_type_id)
-
- attr_element_name = "#{element_name}][data][#{attr.title}]"
+ attr_element_name = "#{element_name}[#{attr.title}]"
html += '
'+attr.label+' '
html += required_span if attr.required?
+ v = value ? value[attr.title] : nil
if attr.linked_custom_metadata?
html += '
'
- html += attribute_form_element(attr, linked_cm, attr_element_name, element_class,depth+1)
+ html += attribute_form_element(attr, v, attr_element_name, element_class,depth+1)
html += '
'
else
- html += attribute_form_element(attr, linked_cm, attr_element_name, element_class)
+ html += attribute_form_element(attr, v, attr_element_name, element_class)
end
unless attr.description.nil?
@@ -75,13 +71,30 @@ def linked_custom_metadata_form_field(attribute,resource,element_name, element_c
html.html_safe
end
- def sample_multi_form_field(attribute, element_name, value)
+ def sample_form_field(attribute, element_name, value, limit = 1)
+
existing_objects = []
str = Struct.new(:id, :title)
- value.each {|v| existing_objects << str.new(v[:id], v[:title]) if v} if value
+ if value
+ value = [value] unless value.is_a?(Array)
+ value.compact.each do |v|
+ id = v[:id]
+ title = v[:title]
+ title = '
Hidden ' unless Sample.find(id).can_view?
+ existing_objects << str.new(id, title)
+ end
+ end
+
+ typeahead = { query_url: typeahead_samples_path + "?linked_sample_type_id=#{attribute.linked_sample_type.id}",
+ handlebars_template: 'typeahead/controlled_vocab_term' }
objects_input(element_name, existing_objects,
- typeahead: { query_url: typeahead_samples_path + "?linked_sample_type_id=#{attribute.linked_sample_type.id}",
- handlebars_template: 'typeahead/controlled_vocab_term' }, class: 'form-control')
+ typeahead: typeahead,
+ limit: limit,
+ class: 'form-control')
+ end
+
+ def sample_multi_form_field(attribute, element_name, value)
+ sample_form_field(attribute, element_name, value, nil)
end
def authorised_samples(projects = nil)
@@ -101,8 +114,12 @@ def sample_attribute_display_title(attribute)
title.html_safe
end
- def display_attribute(sample, attribute, options = {})
- value = sample.get_attribute_value(attribute)
+ def display_attribute(resource, attribute, options = {})
+ value = resource.get_attribute_value(attribute)
+ display_attribute_value(value, attribute, options.merge(resource: resource))
+ end
+
+ def display_attribute_value(value, attribute, options = {})
if value.blank?
text_or_not_specified(value)
else
@@ -124,9 +141,11 @@ def display_attribute(sample, attribute, options = {})
when Seek::Samples::BaseType::CV_LIST
value.each{|v| seek_cv_attribute_display(v, attribute) }.join(', ')
when Seek::Samples::BaseType::LINKED_CUSTOM_METADATA
- linked_custom_metadata_attribute_display(value)
+ linked_custom_metadata_attribute_display(value, attribute)
+ when Seek::Samples::BaseType::LINKED_CUSTOM_METADATA_MULTI
+ linked_custom_metadata_multi_attribute_display(value, attribute)
else
- default_attribute_display(attribute, options, sample, value)
+ default_attribute_display(value, attribute, options)
end
end
end
@@ -140,19 +159,36 @@ def seek_cv_attribute_display(value, attribute)
content
end
- def linked_custom_metadata_attribute_display(value)
+ def linked_custom_metadata_attribute_display(value, attribute)
html = ''
html += '
'
- CustomMetadata.find(value.id).custom_metadata_attributes.each do |attr|
- html += ''
- html += ''+attr.title+' '+' : '
- html += display_attribute(value,attr)
- html += ' '
+ attribute.linked_custom_metadata_type.custom_metadata_attributes.each do |attr|
+ v = value ? value[attr.title.to_s] : nil
+ html += ''
+ if attr.linked_custom_metadata? || attr.linked_custom_metadata_multi?
+ html += content_tag(:span, class: 'linked_custom_metdata_display') do
+ folding_panel(attr.label, true, id:attr.title) do
+ display_attribute_value(v, attr)
+ end
+ end
+ else
+ html += ''+attr.title+' '+' : '
+ html += display_attribute_value(v, attr)
end
+ html += ' '
+ end
html += ' '
html.html_safe
end
+ def linked_custom_metadata_multi_attribute_display(values, attribute)
+ html = ''
+ values.each do |value|
+ html += linked_custom_metadata_attribute_display(value, attribute)
+ end
+ html.html_safe
+ end
+
def seek_sample_attribute_display(value)
if value.kind_of?(Array)
value.map {|v| seek_resource_attribute_display(Sample,v)} .join(", ").html_safe
@@ -178,14 +214,14 @@ def seek_resource_attribute_display(clz, value)
end
end
- def default_attribute_display(attribute, options, sample, value)
- resolution = attribute.resolve (value)
- if (resolution != nil)
+ def default_attribute_display(value, attribute, options)
+ resolution = attribute.resolve(value)
+ if resolution
link_to(value, resolution, target: :_blank)
- else if options[:link] && attribute.is_title
- link_to(value, sample)
+ else
+ if options[:link] && options[:resource] && attribute.is_title
+ link_to(value, options[:resource])
else
-
text_or_not_specified(value, auto_link: options[:link])
end
end
@@ -265,8 +301,7 @@ def show_sample_extraction_status?(data_file)
private
- def attribute_form_element(attribute, resource, element_name, element_class, depth=1)
- value = resource.get_attribute_value(attribute.title)
+ def attribute_form_element(attribute, value, element_name, element_class, depth=1)
placeholder = "e.g. #{attribute.sample_attribute_type.placeholder}" unless attribute.sample_attribute_type.placeholder.blank?
case attribute.sample_attribute_type.base_type
@@ -307,14 +342,13 @@ def attribute_form_element(attribute, resource, element_name, element_class, dep
when Seek::Samples::BaseType::CV_LIST
controlled_vocab_list_form_field attribute.sample_controlled_vocab, element_name, value
when Seek::Samples::BaseType::SEEK_SAMPLE
- terms = attribute.linked_sample_type.samples.authorized_for('view').to_a
- options = options_from_collection_for_select(terms, :id, :title, value.try(:[], 'id'))
- select_tag element_name, options,
- include_blank: !attribute.required?, class: "form-control #{element_class}"
+ sample_form_field attribute, element_name, value
when Seek::Samples::BaseType::SEEK_SAMPLE_MULTI
sample_multi_form_field attribute, element_name, value
when Seek::Samples::BaseType::LINKED_CUSTOM_METADATA
- linked_custom_metadata_form_field attribute, resource, element_name, element_class,depth
+ linked_custom_metadata_form_field attribute, value, element_name, element_class,depth
+ when Seek::Samples::BaseType::LINKED_CUSTOM_METADATA_MULTI
+ linked_custom_metadata_multi_form_field attribute, value, element_name, element_class
else
text_field_tag element_name, value, class: "form-control #{element_class}", placeholder: placeholder
end
diff --git a/app/helpers/sharing_permissions_helper.rb b/app/helpers/sharing_permissions_helper.rb
deleted file mode 100644
index 63389141bb..0000000000
--- a/app/helpers/sharing_permissions_helper.rb
+++ /dev/null
@@ -1,225 +0,0 @@
-module SharingPermissionsHelper
-
- ITEMS_NOT_IN_ISA_HASH = {
- "id": "not_isa-tree",
- "data": {
- "loadable": false
- },
- "li_attr": {
- class:"root-node"
- },
- "a_attr": {
-
- },
- "children": [
- ],
- "text": "Not in ISA",
- "state": {
- "opened": true
- }
- }
-
- ALL_INVESTIGATIONS_HASH = {
- "id": "isa-tree",
- "data": {
- "loadable": false
- },
- "li_attr": {
- class:"root-node"
- },
- "a_attr": {
-
- },
- "children": [
- ],
- "text": "ISA",
- "state": {
- "opened": true
- }
- }
-
- def build_tree_json(hash, root_item)
-
- objects = hash[:nodes].map(&:object)
- real_edges = hash[:edges].select { |e| objects.include?(e[0]) }
-
- roots = hash[:nodes].select do |n|
- real_edges.none? { |_parent, child| child == n.object }
- end
-
- nodes = roots.map { |root| create_tree_node(hash, root.object, root_item) }.flatten
- nodes.to_json
- end
-
- def create_tree_node(hash, object, root_item = nil)
-
- child_edges = hash[:edges].select do |parent, _child|
- parent == object
- end
-
- node = hash[:nodes].detect { |n| n.object == object }
-
- entry = {
- id: unique_node_id(object),
- data: { loadable: false },
- li_attr: { 'data-node-id' => node_id(object) },
- children: []
- }
-
- entry[:text] = object.title
- entry[:icon] = asset_path(resource_avatar_path(object) || icon_filename_for_key("#{object.class.name.downcase}_avatar"))
-
- filtered_child_edges = child_edges.reject { |c| (c[1].instance_of? Publication) || (c[1].instance_of?(Seek::ObjectAggregation))}
- child_edges_with_permission = filtered_child_edges.select { |c| c[1].can_manage? }
-
- unless child_edges_with_permission.blank?
- entry[:children] += child_edges_with_permission.map { |c| create_tree_node(hash, c[1], root_item) }
- end
-
- if node.child_count > 0
- if node.child_count > child_edges.count
- entry[:children] << {
- id: unique_child_count_id(object),
- parent: entry[:id],
- text: "Show #{node.child_count - child_edges.count} more",
- a_attr: { class: 'child-count-leaf' },
- li_attr: { 'data-node-id' => child_count_id(object) },
- data: { child_count: true }
- }
- end
- entry[:state] = { opened: false }
- else
- entry[:state] = { opened: false }
- end
- entry
- end
-
- def add_permissions_to_tree_json (parent_node)
-
- parent_node.each do |node|
- node["li_attr"][:class] = "asset-node-row"
- node["a_attr"] = {}
- node["a_attr"][:class] = "asset-node"
-
- if !node["children"].nil? && node["children"].size > 0
- add_permissions_to_tree_json (node["children"])
- end
- add_asset_permission_nodes(node)
- end
- parent_node
- end
-
- def add_asset_permission_nodes(parent_node)
- asset_type = parent_node["id"].split("-")[0]
- asset_id = parent_node["id"].split("-")[1].to_i
-
- # get asset instance
- asset = safe_class_lookup(asset_type.camelize).find(asset_id)
- parent_node["text"] = "#{h(asset.title)} #{icon_link_to("", "new_window", asset , options = {target:'blank',class:'asset-icon',:onclick => 'window.open(this.href, "_blank");'})}"
-
- permissions_array = get_permission(asset)
- parent_node["children"] = permissions_array + parent_node["children"]
- parent_node
- end
-
- def asset_node_json(resource_type, resource_items)
-
- parent = {
- id: resource_type+"-not_isa",
- data: { loadable: false },
- li_attr: {class:"asset-type-node"},
- a_attr: {},
- children: [],
- text: resource_type
- }
-
- resource_items.each do |item|
-
- entry_item = {
- id: unique_node_id(item),
- data: { loadable: false },
- li_attr: { 'data-node-id' => node_id(item), class:"asset-node-row"},
- a_attr: {class:"asset-node"},
- children: [] ,
- icon: asset_path(resource_avatar_path(item) || icon_filename_for_key("#{item.class.name.downcase}_avatar")),
- text: "#{h(item.title)} #{icon_link_to("", "new_window", item , options = {target:'blank',class:'asset-icon',:onclick => 'window.open(this.href, "_blank");'})}"
- }
-
- permissions_array = get_permission(item)
- entry_item[:children] = permissions_array
- parent[:children].append(entry_item)
- end
- parent
- end
-
-
- def create_policy_node(item, policy_text,sharing_policy_changed)
-
- entry = {
- id: unique_policy_node_id(item),
- data: { loadable: false },
- li_attr: { 'data-node-id' => "Permission-"+node_id(item), class:"hide_permission" },
- a_attr: { class:"permission-node #{sharing_policy_changed}"},
- children: [],
- text:policy_text
- }
- entry
- end
-
- def get_permission (item)
-
- policy =[]
-
- # policy
- downloadable = item.try(:is_downloadable?)
- policy_text = "#{Policy.get_access_type_wording(item.policy.access_type, downloadable)} by Public"
- sharing_policy_changed = (@batch_sharing_permission_changed && (@items_for_sharing.include? item) && !@policy_params[:access_type].nil?)? "sharing_permission_changed" : ""
-
- policy.append(create_policy_node(item,policy_text,sharing_policy_changed))
-
- #permission
- option = {:onclick => 'window.open(this.href, "_blank");'}
-
- item.policy.permissions.map do |permission|
- case permission.contributor_type
- when Permission::PROJECT
- m = Project.find(permission.contributor_id)
- policy_text ="#{Policy.get_access_type_wording(permission.access_type, downloadable)} by Project #{link_to(h(m.title), m, option)}"
- sharing_policy_changed = @batch_sharing_permission_changed && (@items_for_sharing.include? item) ? PolicyHelper::permission_changed_item_class(permission, @policy_params) : ""
- policy.append(create_policy_node(item,policy_text,sharing_policy_changed))
- when Permission::WORKGROUP
- m = WorkGroup.find(permission.contributor_id)
- institution = Institution.find(m.institution_id)
- project = Project.find(m.project_id)
- policy_text ="#{Policy.get_access_type_wording(permission.access_type, downloadable)} by #{link_to(h(project.title), project,option)} @ #{link_to(h(institution.title), institution,option)}"
- sharing_policy_changed = @batch_sharing_permission_changed && (@items_for_sharing.include? item) ? PolicyHelper::permission_changed_item_class(permission, @policy_params) : ""
- policy.append(create_policy_node(item,policy_text,sharing_policy_changed))
- when Permission::INSTITUTION
- m = Institution.find(permission.contributor_id)
- policy_text ="#{Policy.get_access_type_wording(permission.access_type, downloadable)} by Institution #{link_to(h(m.title), m,option)}"
- sharing_policy_changed = @batch_sharing_permission_changed && (@items_for_sharing.include? item) ? PolicyHelper::permission_changed_item_class(permission, @policy_params) : ""
- policy.append(create_policy_node(item,policy_text,sharing_policy_changed))
- when Permission::PERSON
- m = Person.find(permission.contributor_id)
- policy_text ="#{Policy.get_access_type_wording(permission.access_type, downloadable)} by People #{link_to(h(m.title), m,option)}"
- sharing_policy_changed = @batch_sharing_permission_changed && (@items_for_sharing.include? item) ? PolicyHelper::permission_changed_item_class(permission, @policy_params) : ""
- policy.append(create_policy_node(item,policy_text,sharing_policy_changed))
- when Permission::PROGRAMME
- m = Programme.find(permission.contributor_id)
- policy_text ="#{Policy.get_access_type_wording(permission.access_type, downloadable)} by Programme #{link_to(h(m.title), m,option)}"
- sharing_policy_changed = @batch_sharing_permission_changed && (@items_for_sharing.include? item) ? PolicyHelper::permission_changed_item_class(permission, @policy_params) : ""
- policy.append(create_policy_node(item,policy_text,sharing_policy_changed))
- end
- end
- policy
- end
-
-
- private
-
- def unique_policy_node_id(object)
- "Permission-#{node_id(object)}-#{rand(2**32).to_s(36)}"
- end
-
-
-end
diff --git a/app/helpers/workflows_helper.rb b/app/helpers/workflows_helper.rb
index ca875639ca..a447ff61e1 100644
--- a/app/helpers/workflows_helper.rb
+++ b/app/helpers/workflows_helper.rb
@@ -49,6 +49,10 @@ def maturity_badge(level)
content_tag(:span, t("maturity_level.#{level}"), class: "maturity-level label #{label_class}")
end
+ def life_monitor_status_page_url(resource, base: Seek::Config.life_monitor_ui_url)
+ URI.join(base, "/workflow;uuid=#{resource.uuid}").to_s
+ end
+
def test_status_badge(resource)
status = resource.test_status
case status
@@ -65,9 +69,8 @@ def test_status_badge(resource)
label_class = 'label-default'
label = t('test_status.not_available')
end
- url = LifeMonitor::Rest::Client.status_page_url(resource)
- link_to(url, class: 'lifemonitor-status btn btn-default', target: '_blank', rel: 'noopener',
- 'data-tooltip' => 'Click to view in LifeMonitor') do
+ link_to(life_monitor_status_page_url(resource), class: 'lifemonitor-status btn btn-default', target: '_blank',
+ rel: 'noopener', 'data-tooltip' => 'Click to view in LifeMonitor') do
image('life_monitor_icon', class: 'icon lifemonitor-logo') +
'Tests ' +
content_tag(:span, label, class: "test-status label #{label_class}")
diff --git a/app/models/assay.rb b/app/models/assay.rb
index d8bb9b9a68..13b2b9279e 100644
--- a/app/models/assay.rb
+++ b/app/models/assay.rb
@@ -77,7 +77,7 @@ def short_description
end
def state_allows_delete?(*args)
- assets.empty? && publications.empty? && super
+ assets.empty? && publications.empty? && associated_samples_through_sample_type.empty? && super
end
# returns true if this is a modelling class of assay
@@ -90,6 +90,10 @@ def is_experimental?
!assay_class.nil? && assay_class.key == 'EXP'
end
+ def associated_samples_through_sample_type
+ (sample_type.nil? || sample_type.samples.nil?) ? [] : sample_type.samples
+ end
+
# Create or update relationship of this assay to another, with a specific relationship type and version
def associate(asset, options = {})
if asset.is_a?(Organism)
diff --git a/app/models/concerns/has_custom_metadata.rb b/app/models/concerns/has_custom_metadata.rb
index c618cd5344..92585f76aa 100644
--- a/app/models/concerns/has_custom_metadata.rb
+++ b/app/models/concerns/has_custom_metadata.rb
@@ -9,7 +9,7 @@ def custom_metadata_attribute_values_for_search
class_methods do
def has_extended_custom_metadata
- has_one :custom_metadata, as: :item, dependent: :destroy
+ has_one :custom_metadata, as: :item, dependent: :destroy, autosave: true
accepts_nested_attributes_for :custom_metadata
if Seek::Config.solr_enabled
diff --git a/app/models/custom_metadata.rb b/app/models/custom_metadata.rb
index 9831795302..26edcf2248 100644
--- a/app/models/custom_metadata.rb
+++ b/app/models/custom_metadata.rb
@@ -5,31 +5,10 @@ class CustomMetadata < ApplicationRecord
belongs_to :custom_metadata_type, validate: true
belongs_to :custom_metadata_attribute
- has_many :custom_metadata_resource_links, inverse_of: :custom_metadata, dependent: :destroy
- has_many :linked_custom_metadatas, through: :custom_metadata_resource_links, source: :resource, source_type: 'CustomMetadata', dependent: :destroy
- accepts_nested_attributes_for :linked_custom_metadatas
-
validates_with CustomMetadataValidator
- validates_associated :linked_custom_metadatas
delegate :custom_metadata_attributes, to: :custom_metadata_type
-
- after_create :update_linked_custom_metadata_id, if: :has_linked_custom_metadatas?
-
- def update_linked_custom_metadata_id
- linked_custom_metadatas.each do |cm|
- attr_name = cm.custom_metadata_attribute.title
- data.mass_assign(data.to_hash.update({attr_name => cm.id}), pre_process: false)
- update_column(:json_metadata, data.to_json)
- end
- end
-
- def has_linked_custom_metadatas?
- linked_custom_metadatas.any?
- end
-
-
# for polymorphic behaviour with sample
alias_method :metadata_type, :custom_metadata_type
@@ -43,36 +22,4 @@ def custom_metadata_type=(type)
def attribute_class
CustomMetadataAttribute
end
-
- def update_linked_custom_metadata(parameters)
- cmt_id = parameters[:custom_metadata_type_id]
-
- # return no custom metdata is filled
- seek_cm_attrs = CustomMetadataType.find(cmt_id).custom_metadata_attributes.select(&:linked_custom_metadata?)
- return if seek_cm_attrs.blank?
-
- seek_cm_attrs.each do |cma|
- cma_params = parameters[:data][cma.title.to_sym]
- self.set_linked_custom_metadatas(cma, cma_params) unless cma_params.nil?
-
- cma_linked_cmt = cma.linked_custom_metadata_type.attributes_with_linked_custom_metadata_type
-
- unless cma_linked_cmt.blank?
- cm = self.linked_custom_metadatas.select{|cm| cm.custom_metadata_type.id == cma[:linked_custom_metadata_type_id]}.first
- cm.update_linked_custom_metadata(cma_params)
- end
-
- end
- end
-
- def set_linked_custom_metadatas(cma, cm_params)
-
- if self.new_record?
- self.linked_custom_metadatas.build(custom_metadata_type: cma.linked_custom_metadata_type, data: cm_params[:data], custom_metadata_attribute_id: cm_params[:custom_metadata_attribute_id])
- else
- linked_cm = self.linked_custom_metadatas.select{|cm| cm.custom_metadata_type_id.to_s == cm_params[:custom_metadata_type_id]}.select{|cm|cm.custom_metadata_attribute==cma}.first
- linked_cm.update(cm_params.permit!)
- end
- end
-
end
diff --git a/app/models/custom_metadata_resource_link.rb b/app/models/custom_metadata_resource_link.rb
deleted file mode 100644
index 2d77cb1984..0000000000
--- a/app/models/custom_metadata_resource_link.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-class CustomMetadataResourceLink < ApplicationRecord
- belongs_to :custom_metadata
- belongs_to :resource, polymorphic: true
-end
diff --git a/app/models/data_file.rb b/app/models/data_file.rb
index e77a9a6565..d46c400947 100644
--- a/app/models/data_file.rb
+++ b/app/models/data_file.rb
@@ -150,7 +150,7 @@ def extract_samples(sample_type, confirm = false, overwrite = false)
sample.project_ids = project_ids
sample.contributor = contributor
sample.originating_data_file = self
- sample.policy = policy
+ sample.policy = policy.deep_copy
sample.save if sample.valid? && confirm
extracted << sample
diff --git a/app/models/event.rb b/app/models/event.rb
index 912f6749fd..604e442be3 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -39,6 +39,9 @@ class Event < ApplicationRecord
validates :country, country:true, allow_blank: true
+ has_filter :country
+ has_filter start_date: Seek::Filtering::DateFilter.new(field: :start_date)
+
validate :validate_data_files
def validate_data_files
df = data_files.to_a
diff --git a/app/models/sample.rb b/app/models/sample.rb
index 865129a58e..cb965a3a41 100644
--- a/app/models/sample.rb
+++ b/app/models/sample.rb
@@ -16,8 +16,6 @@ class Sample < ApplicationRecord
acts_as_asset
- validates :projects, presence: true, projects: { self: true }
-
belongs_to :sample_type, inverse_of: :samples
alias_method :metadata_type, :sample_type
@@ -32,18 +30,19 @@ class Sample < ApplicationRecord
has_many :linked_samples, through: :sample_resource_links, source: :resource, source_type: 'Sample'
has_many :linking_samples, through: :reverse_sample_resource_links, source: :sample
+ validates :projects, presence: true, projects: { self: true }
validates :title, :sample_type, presence: true
validates_with SampleAttributeValidator
+ validate :validate_added_linked_sample_permissions
before_validation :set_title_to_title_attribute_value
+ before_validation :update_sample_resource_links
- before_save :update_sample_resource_links
after_save :queue_sample_type_update_job
after_save :queue_linking_samples_update_job
after_destroy :queue_sample_type_update_job
-
has_filter :sample_type
def sample_type=(type)
@@ -90,10 +89,6 @@ def referenced_samples
referenced_resources.select { |r| r.is_a?(Sample) }
end
- def state_allows_edit?(*args)
- (id.nil? || originating_data_file.nil?) && super
- end
-
def extracted?
!!originating_data_file
end
@@ -208,6 +203,7 @@ def queue_linking_samples_update_job
end
def update_sample_resource_links
+ return unless sample_type.present?
self.strains = referenced_strains
self.linked_samples = referenced_samples
end
@@ -225,4 +221,18 @@ def update_sample_type_hash(sample_type_hash, sample_type)
end
sample_type_hash
end
+
+ # checks and validates whether new linked samples have view permission, but ignores existing ones
+ def validate_added_linked_sample_permissions
+ return if $authorization_checks_disabled
+ return if linked_samples.empty?
+ previous_linked_samples = []
+ unless new_record?
+ previous_linked_samples = Sample.find(id).referenced_samples
+ end
+ additions = linked_samples - previous_linked_samples
+ if additions.detect { |sample| !sample.can_view? }
+ errors.add(:linked_samples, 'includes a new private sample')
+ end
+ end
end
diff --git a/app/models/sample_attribute.rb b/app/models/sample_attribute.rb
index 98b3416f75..81a4452df9 100644
--- a/app/models/sample_attribute.rb
+++ b/app/models/sample_attribute.rb
@@ -10,6 +10,7 @@ class SampleAttribute < ApplicationRecord
validates :sample_type, presence: true
validates :pid, format: { with: URI::regexp, allow_blank: true, allow_nil: true, message: 'not a valid URI' }
+ validate :validate_against_editing_constraints, if: -> { sample_type.present? }
before_save :store_accessor_name
before_save :default_pos, :force_required_when_is_title
@@ -53,6 +54,10 @@ def short_pid
URI.parse(pid).fragment || pid.gsub(/.*\//,'') || pid
end
+ def linked_custom_metadata_type
+ nil
+ end
+
private
def store_accessor_name
@@ -70,4 +75,22 @@ def force_required_when_is_title
true
end
+ def validate_against_editing_constraints
+ c = sample_type.editing_constraints
+ error_message = "cannot be changed (#{title_was})" # Use pre-change title in error message.
+
+ errors.add(:title, error_message) if title_changed? && !c.allow_name_change?(self)
+
+ unless c.allow_required?(self)
+ errors.add(:is_title, error_message) if is_title_changed?
+ errors.add(:required, error_message) if required_changed?
+ end
+
+ unless c.allow_type_change?(self)
+ errors.add(:sample_attribute_type, error_message) if sample_attribute_type_id_changed?
+ errors.add(:sample_controlled_vocab, error_message) if sample_controlled_vocab_id_changed?
+ errors.add(:linked_sample_type, error_message) if linked_sample_type_id_changed?
+ errors.add(:unit, error_message) if unit_id_changed?
+ end
+ end
end
diff --git a/app/models/sample_attribute_type.rb b/app/models/sample_attribute_type.rb
index 79cdbdd895..af109086a0 100644
--- a/app/models/sample_attribute_type.rb
+++ b/app/models/sample_attribute_type.rb
@@ -88,6 +88,10 @@ def linked_custom_metadata?
base_type == Seek::Samples::BaseType::LINKED_CUSTOM_METADATA
end
+ def linked_custom_metadata_multi?
+ base_type == Seek::Samples::BaseType::LINKED_CUSTOM_METADATA_MULTI
+ end
+
def seek_sample?
base_type == Seek::Samples::BaseType::SEEK_SAMPLE
end
diff --git a/app/models/sample_type.rb b/app/models/sample_type.rb
index 850445d9bf..8433263181 100644
--- a/app/models/sample_type.rb
+++ b/app/models/sample_type.rb
@@ -47,8 +47,11 @@ class SampleType < ApplicationRecord
validates :title, length: { maximum: 255 }
validates :description, length: { maximum: 65_535 }
validates :contributor, presence: true
- validate :validate_one_title_attribute_present, :validate_attribute_title_unique, :validate_attribute_accessor_names_unique,
- :validate_title_is_not_type_of_seek_sample_multi
+ validate :validate_one_title_attribute_present,
+ :validate_attribute_title_unique,
+ :validate_attribute_accessor_names_unique,
+ :validate_title_is_not_type_of_seek_sample_multi,
+ :validate_against_editing_constraints
validates :projects, presence: true, projects: { self: true }
accepts_nested_attributes_for :sample_attributes, allow_destroy: true
@@ -196,6 +199,19 @@ def validate_attribute_accessor_names_unique
end
end
+ def validate_against_editing_constraints
+ c = editing_constraints
+ sample_attributes.each do |a|
+ if a.marked_for_destruction? && !c.allow_attribute_removal?(a)
+ errors.add(:sample_attributes, "cannot be removed, there are existing samples using this attribute (#{a.title})")
+ end
+
+ if a.new_record? && !c.allow_new_attribute?
+ errors.add(:sample_attributes, "cannot be added, new attributes are not allowed (#{a.title})")
+ end
+ end
+ end
+
def attribute_search_terms
attribute_titles
end
diff --git a/app/models/study.rb b/app/models/study.rb
index 944373fc9b..bc1691852e 100644
--- a/app/models/study.rb
+++ b/app/models/study.rb
@@ -2,7 +2,7 @@ class Study < ApplicationRecord
enum status: [:planned, :running, :completed, :cancelled, :failed]
belongs_to :assignee, class_name: 'Person'
-
+
searchable(:auto_index => false) do
text :experimentalists
end if Seek::Config.solr_enabled
@@ -22,7 +22,7 @@ class Study < ApplicationRecord
has_many :sop_versions, through: :assays
has_one :external_asset, as: :seek_entity, dependent: :destroy
-
+
has_and_belongs_to_many :sops
has_and_belongs_to_many :sample_types
@@ -41,7 +41,16 @@ def assets
end
def state_allows_delete? *args
- assays.empty? && super
+ assays.empty? && associated_samples_through_sample_type.empty? && super
+ end
+
+ def associated_samples_through_sample_type
+ return [] if sample_types.nil?
+ st_samples = []
+ sample_types.map do |st|
+ st.samples.map { |sts| st_samples.push sts }
+ end
+ st_samples
end
def clone_with_associations
diff --git a/app/serializers/base_serializer.rb b/app/serializers/base_serializer.rb
index 5083ce6965..09bbdd48c0 100644
--- a/app/serializers/base_serializer.rb
+++ b/app/serializers/base_serializer.rb
@@ -123,20 +123,9 @@ def BaseSerializer.permits policy
attribute :extended_attributes, if: -> { object.respond_to?(:custom_metadata) && !object.custom_metadata.blank? } do
{ extended_metadata_type_id: object.custom_metadata.custom_metadata_type_id.to_s,
- attribute_map: get_custom_metadata }
+ attribute_map: object.custom_metadata.data.to_hash }
end
- def get_custom_metadata
- data = object.custom_metadata.data.to_hash
- CustomMetadata.find(object.custom_metadata.id).custom_metadata_attributes.each do |attr|
- if attr.linked_custom_metadata?
- data[attr.title] = display_custom_metadata(data,attr)
- end
- end
- data
- end
-
-
def show_policy?
return false unless object.respond_to?('can_manage?')
@@ -155,17 +144,6 @@ def submitter
private
- def display_custom_metadata(data,attribute)
- linked_data = CustomMetadata.find(data[attribute.title]).data.to_hash
- CustomMetadata.find(data[attribute.title]).custom_metadata_attributes.each do |attr|
- if attr.linked_custom_metadata?
- linked_data[attr.title] = display_custom_metadata(linked_data,attr)
- end
- end
-
- linked_data
- end
-
def determine_submitter(object)
return object.owner if object.respond_to?('owner')
result = object.contributor if object.respond_to?('contributor') && !object.is_a?(Permission)
diff --git a/app/validators/custom_metadata_validator.rb b/app/validators/custom_metadata_validator.rb
index c73b9cb1d1..a2f6ae13e5 100644
--- a/app/validators/custom_metadata_validator.rb
+++ b/app/validators/custom_metadata_validator.rb
@@ -1,16 +1,33 @@
class CustomMetadataValidator < ActiveModel::Validator
-
def validate(record)
record.custom_metadata_attributes.each do |attribute|
val = record.get_attribute_value(attribute)
- if attribute.test_blank?(val)
- record.errors.add(attribute.title, 'is required') if attribute.required?
- else
- unless attribute.validate_value?(val)
- record.errors.add(attribute.title, "is not a valid #{attribute.sample_attribute_type.title}")
+ validate_attribute(record, attribute, val)
+ end
+ end
+
+ private
+
+ def validate_attribute(record, attribute, value, prefix = '')
+ if attribute.test_blank?(value)
+ record.errors.add("#{prefix}#{attribute.title}", 'is required') if attribute.required?
+ else
+ unless attribute.validate_value?(value)
+ record.errors.add("#{prefix}#{attribute.title}", "is not a valid #{attribute.sample_attribute_type.title}")
+ end
+ end
+
+ if attribute.linked_custom_metadata?
+ attribute.linked_custom_metadata_type.custom_metadata_attributes.each do |attr|
+ validate_attribute(record, attr, value ? value[attr.accessor_name.to_s] : nil, "#{attribute.title}.")
+ end
+ elsif attribute.linked_custom_metadata_multi?
+ linked_attributes = attribute.linked_custom_metadata_type.custom_metadata_attributes
+ value.each_with_index do |val, index|
+ linked_attributes.each do |attr|
+ validate_attribute(record, attr, val ? val[attr.accessor_name.to_s] : nil, "#{attribute.title}.#{index + 1}.")
end
end
end
end
-
end
\ No newline at end of file
diff --git a/app/validators/license_validator.rb b/app/validators/license_validator.rb
index 1ca5fefb7d..047e83dd43 100644
--- a/app/validators/license_validator.rb
+++ b/app/validators/license_validator.rb
@@ -2,7 +2,15 @@ class LicenseValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if Seek::License.find(value)
- record.errors.add(attribute, options[:message] || "isn't a valid license ID")
+ # Try looking up by URI
+ if value.start_with? /https?:/
+ id = Seek::License.uri_to_id(value)
+ if id
+ record.send("#{attribute}=", id)
+ return
+ end
+ end
+ record.errors.add(attribute, options[:message] || "isn't a recognized license")
end
end
\ No newline at end of file
diff --git a/app/views/admin/features_enabled.html.erb b/app/views/admin/features_enabled.html.erb
index 63039940a4..f46346c9d5 100644
--- a/app/views/admin/features_enabled.html.erb
+++ b/app/views/admin/features_enabled.html.erb
@@ -193,11 +193,13 @@
<%= admin_text_setting(:life_monitor_url, Seek::Config.life_monitor_url,
- 'LifeMonitor URL', "The URL of a LifeMonitor instance.") %>
+ 'LifeMonitor API URL', "The API URL of a LifeMonitor instance.") %>
<%= admin_text_setting(:life_monitor_client_id, Seek::Config.life_monitor_client_id,
'LifeMonitor OAuth client ID', 'The ID for this application to authenticate users through the LifeMonitor OAuth provider.') %>
<%= admin_text_setting(:life_monitor_client_secret, Seek::Config.life_monitor_client_secret,
'LifeMonitor OAuth client secret', 'The secret token for this application to authenticate users through the LifeMonitor OAuth provider.') %>
+ <%= admin_text_setting(:life_monitor_ui_url, Seek::Config.life_monitor_ui_url,
+ 'LifeMonitor UI URL', "The UI (app) URL of a LifeMonitor instance.") %>
diff --git a/app/views/admin/settings.html.erb b/app/views/admin/settings.html.erb
index 87068624e8..5296ef1fb0 100644
--- a/app/views/admin/settings.html.erb
+++ b/app/views/admin/settings.html.erb
@@ -56,22 +56,29 @@
admin_dropdown_setting(:max_all_visitors_access_type, option_tags, 'Permission Limits',
'Maximum permission option for all visitors, including those without a login') %>
- <%= admin_setting_block('Default License', "The default license to use when one is not specified by a #{t('project').pluralize}.") do
- grouped_license_select(:default_license, Seek::Config.default_license, id: 'license-select',
- class: 'form-control', source: Seek::License.open_definition[:data])
- end %>
-
- <%= admin_setting_block('Recommended data licenses', "The licenses to recommend when data, such as a #{t('data_file')} or #{t('document')}, is registered. Hold down CTRL (or Command on Mac) to select multiple or to deselect.") do
- select_tag :recommended_data_licenses, options_for_select(Seek::License.open_definition[:data].map { |l| [l['title'], l['id']]}, Seek::Config.recommended_data_licenses), multiple: true, class: 'form-control'
- end %>
-
- <%= admin_setting_block('Recommended software licenses', "The licenses to recommend when software such as a #{t('workflow')}, is registered. Hold down CTRL (or Command on Mac) to select multiple or to deselect.") do
- select_tag :recommended_software_licenses, options_for_select(Seek::License.open_definition[:software].map { |l| [l['title'], l['id']]}, Seek::Config.recommended_software_licenses), multiple: true, class: 'form-control'
- end %>
+ <%= admin_setting_block('Default License', "The default license to use when one is not specified by a #{t('project').pluralize}.") do %>
+ <%= license_select(:default_license, Seek::Config.default_license, id: 'license-select', class: 'form-control') %>
+ <% end %>
+
+ <%= admin_setting_block('Recommended data licenses', "The licenses to recommend when data, such as a #{t('data_file')} or #{t('document')}, is registered.") do %>
+ <%= associations_list('recommended-data-licenses', 'associations/general',
+ Seek::Config.recommended_data_licenses.map { |id| { id: id, title: Seek::License.find(id).title } }.to_json,
+ 'data-field-name' => 'recommended_data_licenses',
+ empty_text: 'No recommended licenses') %>
+ <%= license_select(:_recommended_data_license_select, nil, prompt: 'Select a license to add it to the list...', class: 'form-control') %>
+ <% end %>
+
+ <%= admin_setting_block('Recommended software licenses', "The licenses to recommend when software, such as a #{t('workflow')}, is registered.") do %>
+ <%= associations_list('recommended-software-licenses', 'associations/general',
+ Seek::Config.recommended_software_licenses.map { |id| { id: id, title: Seek::License.find(id).title } }.to_json,
+ 'data-field-name' => 'recommended_software_licenses',
+ empty_text: 'No recommended licenses') %>
+ <%= license_select(:_recommended_software_license_select, nil, prompt: 'Select a license to add it to the list...', class: 'form-control') %>
+ <% end %>
<%= admin_setting_block('Metadata License', "The license granted on metadata produced by this SEEK instance.") do
- grouped_license_select(:metadata_license, Seek::Config.metadata_license, id: 'metadata-license-select',
- class: 'form-control', source: Seek::License.open_definition[:data])
+ license_select(:metadata_license, Seek::Config.metadata_license, id: 'metadata-license-select',
+ class: 'form-control', source: Seek::License.combined)
end %>
<%= admin_dropdown_setting(:permissions_popup,
@@ -122,3 +129,26 @@
<%= submit_tag "Update", data: { disable_with: 'Updating...' }, :class => 'btn btn-primary' -%> or
<%= cancel_button admin_path %>
<% end -%>
+
+
+
\ No newline at end of file
diff --git a/app/views/assets/_batch_asset_selection.html.erb b/app/views/assets/_batch_asset_selection.html.erb
new file mode 100644
index 0000000000..3f34a53470
--- /dev/null
+++ b/app/views/assets/_batch_asset_selection.html.erb
@@ -0,0 +1,108 @@
+<%
+ publishing ||= false
+ show_hide_blocked ||= false
+ show_permissions ||= false
+ show_managers ||= false
+-%>
+
+
+ <%= render partial: 'assets/batch_selection/buttons', locals: {
+ text: "your items",
+ select_deselect_all: true,
+ collapse_expand: true,
+ show_hide_blocked: publishing,
+ show_hide_permissions: show_permissions
+ } %>
+
+
+
+
+
+ <% @assets.sort_by { |k, v| v.first.class.name }.each do |type, items| %>
+
+
<%= batch_selection_collapse_toggle -%> <%= text_for_resource items.first %>(s)
+
+ <%= render partial: 'assets/batch_selection/buttons', locals: {
+ text: (text_for_resource items.first).downcase.pluralize,
+ show_hide_blocked: publishing,
+ select_deselect_all: true
+ } %>
+ <% items.each do |item| %>
+ <%= render partial: 'assets/batch_selection/asset_row',
+ object: item,
+ locals: { html_classes: 'publishing_options',
+ publishing: publishing,
+ show_permissions: show_permissions,
+ show_managers: show_managers
+ } -%>
+ <% end %>
+
+
+ <% end %>
+
+
+
+ <% unless @assets_not_in_isa.empty? %>
+
+
<%= batch_selection_collapse_toggle -%> Items not in ISA
+
+ <%= render partial: 'assets/batch_selection/buttons', locals: {
+ text: "items not in ISA",
+ show_hide_blocked: publishing,
+ select_deselect_all: true
+ } %>
+ <% @assets_not_in_isa.each do |item| %>
+ <%= render partial: 'assets/batch_selection/asset_row',
+ object: item,
+ locals: { html_classes: "publishing_options",
+ publishing: publishing,
+ show_permissions: show_permissions,
+ show_managers: show_managers
+ } -%>
+ <% end %>
+
+
+ <% end %>
+
+ <% unless @investigations.empty? %>
+
+
<%= batch_selection_collapse_toggle-%> Items in ISA
+
+ <%= render partial: 'assets/batch_selection/buttons', locals: {
+ text: "items in ISA",
+ select_deselect_all: true,
+ collapse_expand: true,
+ show_hide_blocked: show_hide_blocked
+ } %>
+
+ <% @investigations.each do |inv| %>
+ <% collection = inv.assays.map(&:study).map(&:investigation).flatten.uniq %>
+ <% collection = inv.studies.map(&:investigation).flatten.uniq if collection.empty? %>
+ <% collection = [inv] if collection.empty?%>
+ <%= render partial: 'assets/batch_selection/asset_row',
+ locals: { publishing: publishing,
+ show_permissions: show_permissions,
+ show_managers: show_managers,
+ show_children: true
+ },
+ collection: collection %>
+ <% end %>
+
+
+
+ <% end %>
+
+
+
+
diff --git a/app/views/assets/_license_selector.html.erb b/app/views/assets/_license_selector.html.erb
index d8091c5ecd..43caab681f 100644
--- a/app/views/assets/_license_selector.html.erb
+++ b/app/views/assets/_license_selector.html.erb
@@ -27,10 +27,10 @@
<%= label %>
- <%= grouped_license_select("#{resource.class.name.underscore}[#{accessor.to_s}]", selected_license,
+ <%= license_select("#{resource.class.name.underscore}[#{accessor.to_s}]", selected_license,
id: 'license-select', class: 'form-control',
data: { 'can-overwrite': using_default },
- source: Seek::License.open_definition[:all],
+ source: Seek::License.combined,
recommended: recommended_licenses) %>
@@ -38,10 +38,3 @@
<% end %>
-
-
diff --git a/app/views/assets/batch_selection/_asset_row.html.erb b/app/views/assets/batch_selection/_asset_row.html.erb
new file mode 100644
index 0000000000..0390f0982b
--- /dev/null
+++ b/app/views/assets/batch_selection/_asset_row.html.erb
@@ -0,0 +1,104 @@
+<%
+ item = asset_row
+ preselected ||= nil
+ checked ||= (item == preselected)
+ publishing ||= false
+ can_manage = item.can_manage?
+ can_view = item.can_view?
+ published = false
+ html_classes ||= "publishing_options"
+ tree_class = 'not-manageable'
+ tree_class = 'manageable' if can_manage
+ tree_class = 'not-visible' unless can_view
+ if publishing
+ if item.is_published?
+ published = true
+ tree_class = 'already-published'
+ end
+ end
+ item_id = "#{item.class.name}_#{item.id}"
+ show_managers ||= false
+ show_permissions ||= false
+ show_managers = show_managers && (can_view || item.can_see_hidden_item?(current_user.person))
+ show_children ||= false
+ children = []
+ if show_children
+ case item
+ when Investigation
+ children = item.studies
+ when Study
+ children = item.assays
+ when Assay
+ children = item.assets
+ end
+ end
+-%>
+
+
+ <%= batch_selection_collapse_toggle if children.any? %>
+
+ <%= render partial: 'assets/batch_selection/checkbox',
+ locals: { checkbox_id: publishing_item_param(item),
+ checkbox_class: item_id,
+ checked: can_view && checked,
+ not_visible: !can_view,
+ published: can_view && published,
+ cant_manage: !can_manage,
+ has_children: children.any? } -%>
+
+
+ <%= text_for_resource item -%>:
+ <% if can_view %>
+ <%= link_to item.title, item, target: "_blank" -%>
+ <% else %>
+ This item is hidden to you
+ <% end %>
+
+
+ <% if show_permissions %>
+ <% if can_view %>
+
+ <%= list_item_visibility(item)-%>
+
+ <% else %>
+ <%= list_item_visibility(item)-%>
+ <% end %>
+ <% end %>
+
+ <% if show_managers %>
+
+
+
+ <% end %>
+
+
+ <% if show_managers %>
+
+ Manageable by:
+ <% if item.managers.empty? %>
+ None
+ <% else %>
+ <%= item.managers.collect { |m| link_to(h(m.title), m) }.join(", ").html_safe -%>
+ <% end %>
+
+ <% end %>
+ <% if show_permissions && can_view %>
+ <%= render partial: 'assets/batch_selection/permission_list', locals: { item: item } -%>
+ <% end %>
+
+ <% if show_children && children.any? %>
+
+ <% children.each do |child| %>
+ <%= render partial: 'assets/batch_selection/asset_row',
+ object: child,
+ locals: { preselected: preselected,
+ publishing: publishing,
+ html_classes: "publishing_options",
+ show_permissions: show_permissions,
+ show_managers: show_managers,
+ show_children: true
+ } -%>
+ <% end %>
+
+ <% end %>
+
diff --git a/app/views/assets/batch_selection/_buttons.html.erb b/app/views/assets/batch_selection/_buttons.html.erb
new file mode 100644
index 0000000000..52b856cc25
--- /dev/null
+++ b/app/views/assets/batch_selection/_buttons.html.erb
@@ -0,0 +1,50 @@
+<%
+ text ||= "your items"
+ select_deselect_all ||= false
+ collapse_expand ||= false
+ show_hide_blocked ||= false
+ show_hide_permissions ||= false
+%>
+
+
diff --git a/app/views/assets/batch_selection/_checkbox.html.erb b/app/views/assets/batch_selection/_checkbox.html.erb
new file mode 100644
index 0000000000..b3da44f54a
--- /dev/null
+++ b/app/views/assets/batch_selection/_checkbox.html.erb
@@ -0,0 +1,44 @@
+<%
+ checkbox_class ||= "no_name" # <- Needed!
+ published ||= false
+ cant_manage ||= false
+ not_visible ||= false
+ checked ||= false
+ has_children ||= false
+-%>
+
+ <% if published %>
+
+
+ Published
+
+ <% elsif not_visible %>
+
+
+
+ <% elsif cant_manage %>
+
+
+
+ <% else %>
+
+ <%= check_box_tag checkbox_id, 1, checked, { class: checkbox_class } -%>
+
+ <% end %>
+
+ <% if has_children %>
+
+
+ Toggle Dropdown
+
+
+ <% end %>
+
diff --git a/app/views/assets/batch_selection/_permission_list.html.erb b/app/views/assets/batch_selection/_permission_list.html.erb
new file mode 100644
index 0000000000..643f7aed42
--- /dev/null
+++ b/app/views/assets/batch_selection/_permission_list.html.erb
@@ -0,0 +1,18 @@
+<%
+ item ||= permission_list
+ downloadable = item.try(:is_downloadable?)
+-%>
+
+ <% sharing_policy_changed = (@batch_sharing_permission_changed && (@items_for_sharing.include? item) && !@policy_params[:access_type].nil?)? "sharing_permission_changed" : "" %>
+
+ Public:
+ <%= Policy.get_access_type_wording(item.policy.access_type, downloadable) %>.
+
+ <% item.policy.permissions.map do |permission| %>
+ <% sharing_permission_changed = @batch_sharing_permission_changed && (@items_for_sharing.include? item) ? PolicyHelper::permission_changed_item_class(permission, @policy_params) : "" %>
+
+ <%= permission_title(permission, member_prefix: false, icon: false, link: true) -%>:
+ <%= Policy.get_access_type_wording(permission.access_type, downloadable) %>
+
+ <% end %>
+
diff --git a/app/views/assets/publishing/_isa_publishing_preview.html.erb b/app/views/assets/publishing/_isa_publishing_preview.html.erb
deleted file mode 100644
index 53779ae75a..0000000000
--- a/app/views/assets/publishing/_isa_publishing_preview.html.erb
+++ /dev/null
@@ -1,33 +0,0 @@
-<%
- item = isa_publishing_preview
-
- case item
- when Investigation
- children = item.studies
- when Study
- children = item.assays
- when Assay
- children = item.assets
- else
- children = []
- end
--%>
-
\ No newline at end of file
diff --git a/app/views/assets/publishing/_options_for_publishing.html.erb b/app/views/assets/publishing/_options_for_publishing.html.erb
deleted file mode 100644
index 403fe471ea..0000000000
--- a/app/views/assets/publishing/_options_for_publishing.html.erb
+++ /dev/null
@@ -1,51 +0,0 @@
-<%
- item = options_for_publishing
- checked ||= false
-
- tree_class = 'not-publishable'
- tree_class = 'publishable' if item.can_publish?
- tree_class = 'already-published' if item.is_published?
-
- toggle ||=false
- cb_parent_selector ||="div\##{item.class.name}_#{item.id}.split_button_parent"
-
--%>
-
- <% if item.can_view? %>
-
- <%= text_for_resource item -%>: <%= link_to item.title, item, :target => "_blank" -%>
- <%=list_item_visibility(item)-%>
-
-
Manageable by <%= item.managers.empty? ? "None ".html_safe : item.managers.collect { |m| link_to(h(m.title), m) }.join(", ").html_safe -%>
- <% else %>
-
<%= text_for_resource item -%>: This item is hidden to you
- <% if current_user.try(:person) && item.can_see_hidden_item?(current_user.person) %>
-
Manageable by <%= item.managers.empty? ? "
None
".html_safe : item.managers.collect { |m| link_to(h(m.title), m) }.join(", ").html_safe -%>
- <% end %>
- <% end %>
-
-
- <% if item.is_published? %>
- <%= render :partial => 'general/split_button_checkbox',
- locals: { checkbox_id: publishing_item_param(item),
- checkbox_class: "#{item.class.name}_#{item.id}",
- published: true,
- toggle: toggle,
- cb_parent_selector: cb_parent_selector} -%>
- <% elsif item.can_publish? %>
- <%= render :partial => 'general/split_button_checkbox',
- locals: { checkbox_id: publishing_item_param(item),
- checkbox_class: "#{item.class.name}_#{item.id}",
- checkbox_text: "Publish?",
- checked: checked,
- toggle: toggle,
- cb_parent_selector: cb_parent_selector} -%>
- <% else %>
-
-
- Can't publish
-
- <% end %>
-
-
-
diff --git a/app/views/assets/publishing/batch_publishing_preview.html.erb b/app/views/assets/publishing/batch_publishing_preview.html.erb
index 625fca6bae..c51dc30cf1 100644
--- a/app/views/assets/publishing/batch_publishing_preview.html.erb
+++ b/app/views/assets/publishing/batch_publishing_preview.html.erb
@@ -11,45 +11,27 @@
- You can select an item to be published by checking the Publish
- checkbox beside that item.
+ You can select an item to be published by checking the checkbox beside that item.
-
-
- Select all your items |
-
- Deselect all your items
-
-<%= form_tag({:action => :check_related_items},:method=>:post) do -%>
+<%= form_tag({action: :check_related_items},method: :post) do -%>
<% if @assets.empty? %>
All your assets are published or you have no assets in <%= Seek::Config.instance_name %>
<%= link_to "Back to profile", person_path(params[:id].to_i) -%>
<% else %>
- <% @assets.sort_by { |k, v| v.first.class.name }.each do |type, items| %>
-
- <% end %>
+ <%= render partial: "assets/batch_asset_selection",
+ locals: { publishing: true,
+ show_hide_blocked: true,
+ show_permissions: true,
+ show_managers: false
+ }
+ -%>
-
- <%= submit_tag "Next",data: { disable_with: 'Next' }, :class => 'btn btn-primary' -%>
+ <%= submit_tag "Next",data: { disable_with: 'Next' }, class: 'btn btn-primary' -%>
Or
<%= cancel_button person_path(params[:id].to_i)-%>
<% end -%>
diff --git a/app/views/assets/publishing/publish_final_confirmation.html.erb b/app/views/assets/publishing/publish_final_confirmation.html.erb
index fc24050d67..d8d815fc50 100644
--- a/app/views/assets/publishing/publish_final_confirmation.html.erb
+++ b/app/views/assets/publishing/publish_final_confirmation.html.erb
@@ -1,21 +1,74 @@
<%= show_title "Confirm publishing" -%>
-
- You are about the publish the following items.
-
-<%= form_tag :action => :publish do %>
-
- <% @items_for_publishing.each do |item| %>
- <%= hidden_field_tag publishing_item_param(item), 1 %>
+
+<% unless @items_for_immediate_publishing.empty? -%>
+ The following items will be published:
+
+
Select "Confirm" to make the following item(s) immediately accessible to the public.
+
+
+<% end -%>
+
+<% unless @waiting_for_publish_items.empty? -%>
+ The following items require approval:
+
+
+ One or more of the items to be published are associated with a <%= t('project') -%>
+ that has chosen to use the protection of the <%= t('asset_gatekeeper').downcase %>.
+ The <%= t('asset_gatekeeper').downcase %> is a person that needs to approve items before they are finally published.
+
+
+ When you click "Confirm" an email will be sent to that person, and they will either approve or reject the publication.
+ Once this has happened, you will be notified back via an email.
+
+
+
+ <% @waiting_for_publish_items.each do |item| %>
+ <%= text_for_resource item -%>
+ : <%= link_to item.title, item, target: "_blank" -%>
+ Approval required from: <%= item.asset_gatekeepers.collect { |m| link_to(m.title, m) }.join(" or ").html_safe -%>
+
+ <% end %>
+
+<% end -%>
+
+<% unless @items_cannot_publish.blank? -%>
+ The following items cannot be published:
+
+
One or more of the items you selected cannot be published.
+
+ It is likely that the item(s) are associated with a <%= t('project') -%>
+ that has chosen to use the protection of the <%= t('asset_gatekeeper').downcase %>,
+ and an existing request is either waiting approval or it has been rejected.
+ Visit the item(s) page to confirm this.
+
+
If you think this is not the case, please contact your system's administrator.
+
+
+ <% @items_cannot_publish.each do |item| %>
+ <%= text_for_resource item -%>
+ : <%= link_to item.title, item, target: "_blank" -%>
+
+ <% end %>
+
+<% end -%>
+
+<%= form_tag action: :publish do %>
+
+ <% @items_for_publishing.each do |item| %>
+ <%= hidden_field_tag publishing_item_param(item), 1 %>
+
+ <% end %>
+
<% resource = (controller_name == 'people') ? current_user.person : @asset %>
-
- <%= submit_tag "Confirm",data: { disable_with: 'Confirm' }, :class => 'btn btn-primary' -%>
+ <%= submit_tag "Confirm", data: { disable_with: 'Confirm' }, class: 'btn btn-primary' -%>
or
<%= cancel_button(resource) %>
<% end %>
diff --git a/app/views/assets/publishing/publish_related_items.html.erb b/app/views/assets/publishing/publish_related_items.html.erb
index 7bb8cdc55e..bb17deaf04 100644
--- a/app/views/assets/publishing/publish_related_items.html.erb
+++ b/app/views/assets/publishing/publish_related_items.html.erb
@@ -5,32 +5,41 @@
- If you have the required access rights, you can choose to publish it by checking the
- Publish checkbox beside the item.
+ If you have the required access rights, you can choose to publish it by checking the checkbox beside the item.
If you do not have the required access rights to publish, the checkbox is
disabled . Somebody that can publish that item is listed next to it and you should contact them and ask them to publish it for you.
-<%= form_tag({:action => :check_gatekeeper_required},:method=>:post) do %>
- <% @items_for_publishing.each do |item| %>
- <% if item.contains_publishable_items? %>
- <% if item.is_asset? %>
- <%= render :partial => "assets/publishing/isa_publishing_preview",
- :collection => item.assays.map(&:study).map(&:investigation).flatten.uniq,
- :locals => { :preselected => item } %>
- <% else %>
- <%= render :partial => "assets/publishing/isa_publishing_preview", :object => item,
- :locals => { :preselected => item } %>
+<%= form_tag({action: :check_gatekeeper_required}, method: :post) do %>
+
+ <%= render partial: 'assets/batch_selection/buttons', locals: {
+ text: "your items",
+ select_deselect_all: true,
+ collapse_expand: true,
+ show_hide_blocked: true,
+ show_hide_permissions: true
+ } %>
+
+ <% @items_for_publishing.each do |item| %>
+ <% if item.contains_publishable_items? %>
+ <% if item.is_asset? %>
+ <%= render partial: "assets/batch_selection/asset_row",
+ collection: item.assays.map(&:study).map(&:investigation).flatten.uniq,
+ locals: { preselected: item, publishing: true, show_permissions: true, show_children: true } %>
+ <% else %>
+ <%= render partial: "assets/batch_selection/asset_row", object: item,
+ locals: { preselected: item, publishing: true, show_permissions: true, show_children: true } %>
+ <% end %>
+ <% else %>
+ <%= check_box_tag publishing_item_param(item), 1, true, {style: 'display:none;'} %>
+ <% end %>
<% end %>
- <% else %>
- <%= check_box_tag publishing_item_param(item), 1, true, {:style => 'display:none;'} %>
- <% end %>
- <% end %>
-
+
+
<% resource = (controller_name == 'people') ? current_user.person : @asset %>
- <%= submit_tag "Next",data: { disable_with: 'Next' }, :class => 'btn btn-primary' -%>
+ <%= submit_tag "Next",data: { disable_with: 'Next' }, class: 'btn btn-primary' -%>
or
<%= cancel_button(resource) %>
<% end %>
diff --git a/app/views/assets/publishing/publish_related_items_confirm.html.erb b/app/views/assets/publishing/publish_related_items_confirm.html.erb
index 07c1a56ac9..5504f7110e 100644
--- a/app/views/assets/publishing/publish_related_items_confirm.html.erb
+++ b/app/views/assets/publishing/publish_related_items_confirm.html.erb
@@ -8,9 +8,9 @@
<% @items_for_publishing.each do |item| %>
- <% if item.is_a?(Assay) || !item.assays.empty? %>
+ <% if item.is_a?(Assay) || (!item.is_a?(Event) && !item.assays.empty?) %>
- <%= text_for_resource item -%>: <%= link_to item.title, item, :target => "_blank" -%>
+ <%= text_for_resource item -%>: <%= link_to item.title, item, target: "_blank" -%>
<% if item.is_published? %>
(already published)
<% end %>
@@ -30,7 +30,7 @@
Would you like to review and publish the associated items?
-<%= form_tag({:action => :publish_related_items}, :method => :post) do %>
+<%= form_tag({action: :publish_related_items}, method: :post) do %>
<% @items_for_publishing.each do |item| %>
<%= check_box_tag publishing_item_param(item), 1, true %>
@@ -40,9 +40,9 @@
<% resource = (controller_name == 'people') ? current_user.person : @asset %>
- <%= submit_tag "OK", :class => 'btn btn-primary' -%>
+ <%= submit_tag "OK", class: 'btn btn-primary' -%>
<% if allow_skip %>
- <%= submit_tag "Skip", :onclick => "this.form.action='check_gatekeeper_required'", :class => 'btn btn-default' -%>
+ <%= submit_tag "Skip", onclick: "this.form.action='check_gatekeeper_required'", class: 'btn btn-default' -%>
<% end %>
<%= cancel_button(:back) -%>
<% end %>
diff --git a/app/views/assets/publishing/waiting_approval_list.html.erb b/app/views/assets/publishing/waiting_approval_list.html.erb
deleted file mode 100644
index 531339fcc4..0000000000
--- a/app/views/assets/publishing/waiting_approval_list.html.erb
+++ /dev/null
@@ -1,48 +0,0 @@
-<%= show_title "One #{t('asset_gatekeeper').downcase } will need to approve the items to be published" -%>
-
-
-
- One or more of the items to be published are associated with a <%= t('project') -%> that has chosen to use the protection of the <%= t('asset_gatekeeper').downcase %>.
-
-
- The <%= t('asset_gatekeeper').downcase %> is a person that needs to approve items before they are finally published.
-
-
- The affected items, and the related <%= t('asset_gatekeeper').downcase %>, are listed below. When you Submit an email will be sent to that person, and they will either approve
- or reject the publication. Once this has happened, you will be notified back via an email.
-
-
-
The following items require approval from one of the <%= t('asset_gatekeeper').downcase.pluralize %>:
-
- <% @waiting_for_publish_items.each do |item| %>
- <%= text_for_resource item -%>
- : <%= link_to item.title, item, :target => "_blank" -%>
- Approval required from: <%= item.asset_gatekeepers.collect { |m| link_to(m.title, m) }.join(" or ").html_safe -%>
-
- <% end %>
-
-<% unless @items_for_immediate_publishing.empty? -%>
-
The following items will be published immediately and do not require approval from the <%= t('asset_gatekeeper').downcase %>:
-
-<% end -%>
-
-<%= form_tag :action => :publish do %>
-
- <% @items_for_publishing.each do |item| %>
- <%= hidden_field_tag publishing_item_param(item), 1 %>
-
- <% end %>
-
-
-
- <% resource = (controller_name == 'people') ? current_user.person : @asset %>
- <%= submit_tag "Confirm", data: { disable_with: 'Confirm' }, :class => 'btn btn-primary' -%>
- or
- <%= cancel_button(resource) %>
-<% end %>
diff --git a/app/views/assets/sharing/batch_sharing_permission_preview.html.erb b/app/views/assets/sharing/batch_sharing_permission_preview.html.erb
index 14f8355a67..991c3c2862 100644
--- a/app/views/assets/sharing/batch_sharing_permission_preview.html.erb
+++ b/app/views/assets/sharing/batch_sharing_permission_preview.html.erb
@@ -1,321 +1,53 @@
<%
- items_not_in_isa_hash = SharingPermissionsHelper::ITEMS_NOT_IN_ISA_HASH
- items_not_in_isa_hash[:children] =[]
-
- all_investigations_hash = SharingPermissionsHelper::ALL_INVESTIGATIONS_HASH
- all_investigations_hash[:children] = []
-
- #include items which can change sharing permissions, the 'publication' is intendedly excluded.
- all_related_items_hash = get_related_resources(current_user.person).slice(*Seek::Util.authorized_types.map(&:name)).except!('Publication')
-
- items_not_in_isa = filter_items_not_in_ISA(all_related_items_hash)
@policy_params = params[:policy_attributes]
%>
+<%= render partial: 'sharing/batch_change_results' %>
<%= show_title "Change permissions of items related to #{link_to(h(current_user.person.name),current_user.person)} in batch".html_safe -%>
- Items are grouped to those included and those not included in the ISA (Investigation-Study-Assay) structure .
- The item list excludes Project , Institution and Publication since these are always publicly visible
- You can view current permissions of each item by clicking the item's name.
+ You can view the details of current permissions for each item by clicking the item's policy icon (
+ <%= image('world', title: 'Was published', class: 'visibility_icon') %>
+ <%= image('partial_world', title: 'Visible to everyone, but not accessible', class: 'visibility_icon') %>
+ <%= image('manage', title: 'Custom policy', class: 'visibility_icon') %>
+ <%= image('lock', title: 'Private', class: 'visibility_icon') %>
+ ).
+ You can view the managers for each item by clicking the
+
+ icon.
After your confirmation, the newly modified permissions will be highlighted with .
-<%= form_tag({:action => :batch_change_permission_for_selected_items}, :method => :post) do -%>
-
- <%= folding_panel("Items not in ISA", false, :id => 'not_isa_item', :body_options => {:id => 'items_fold_content'},
- :help_text => nil) do %>
-
-
<%= link_to "Select All", "#", id: "select_all_not_isa" -%> |
-
<%= link_to "Deselect All", "#", id: "deselect_all_not_isa" -%> |
-
<%= link_to "Expand All", "#", id: "expand_all_not_isa" -%> |
-
<%= link_to "Collapse All", "#", id: "collapse_all_not_isa" -%>
-
-
- <% items_not_in_isa.each do |resource_type, resource_items| %>
- <% asset_node= asset_node_json(resource_type, resource_items) %>
- <% items_not_in_isa_hash[:children].append(asset_node) %>
- <% end %>
-
-
-
- <% end %>
-
-
- <% all_related_items_hash.each do |resource_type, resource_items| %>
- <% if resource_type == "Investigation" %>
- <% resource_items[:items].each do |item| %>
- <% options ||= { depth: 4, parent_depth: nil, sibling_depth: nil, include_self: true } %>
- <% hash = Seek::IsaGraphGenerator.new(item).generate(**options) %>
- <% tree = JSON.parse(build_tree_json(hash, item)) %>
- <% tree = add_permissions_to_tree_json(tree) %>
- <% all_investigations_hash[:children].append(tree.first) %>
- <% end %>
- <% end %>
- <% end %>
-
- <%= folding_panel("Items in ISA: ", false, :id => 'isa_item', :body_options => {:id => 'items_fold_content'},
- :help_text => nil) do %>
-
-
<%= link_to "Select All", "#", id: "select_all_isa" -%> |
-
<%= link_to "Deselect All", "#", id: "deselect_all_isa" -%> |
-
<%= link_to "Expand All", "#", id: "expand_all_isa" -%> |
-
<%= link_to "Collapse All", "#", id: "collapse_all_isa" -%>
-
-
-
+ <%= form_tag({action: :batch_change_permission_for_selected_items}, method: :post) do -%>
+
+ <% if @assets.empty? %>
+
You have no manageable assets in <%= Seek::Config.instance_name %>
+
+
+ <%= link_to "Back to profile", person_path(params[:id].to_i) -%>
+ <% else %>
+ <%= render partial: "assets/batch_asset_selection",
+ locals: { publishing: false,
+ show_hide_blocked: true,
+ show_permissions: true,
+ show_managers: false
+ }
+ -%>
+
+ <%= submit_tag "Next",data: { disable_with: 'Next' }, class: 'btn btn-primary' -%>
+ Or
+ <%= cancel_button person_path(params[:id].to_i)-%>
+ <% end -%>
<% end -%>
-
- <% resource = (controller_name == 'people') ? current_user.person : @asset %>
-
- <%= submit_tag "Next", data: {disable_with: 'Next'}, :class => 'btn btn-primary', :onclick => 'show_all_checkboxes()' -%>
-
- or
- <%= cancel_button(resource, button_text: "Back to profile") %>
-
-<% end -%>
-
diff --git a/app/views/assets/sharing/sharing_bulk_change_preview.html.erb b/app/views/assets/sharing/sharing_bulk_change_preview.html.erb
index 2e78eadd38..1bbb6f93b5 100644
--- a/app/views/assets/sharing/sharing_bulk_change_preview.html.erb
+++ b/app/views/assets/sharing/sharing_bulk_change_preview.html.erb
@@ -13,7 +13,7 @@
<% @items_for_sharing.each do |item| %>
- <%= hidden_field_tag sharing_item_param(item), 1 %>
+ <%= hidden_field_tag publishing_item_param(item), 1 %>
<%= text_for_resource item -%>: <%= link_to item.title, item -%>
<% if item.try(:is_downloadable?) %>
diff --git a/app/views/custom_metadata/_custom_metadata_attribute_values.html.erb b/app/views/custom_metadata/_custom_metadata_attribute_values.html.erb
index d762adbe4d..cdd182b4fb 100644
--- a/app/views/custom_metadata/_custom_metadata_attribute_values.html.erb
+++ b/app/views/custom_metadata/_custom_metadata_attribute_values.html.erb
@@ -6,17 +6,10 @@
-
<% else %>
-
<% end %>
\ No newline at end of file
diff --git a/app/views/custom_metadata/_fancy_linked_custom_metadata_multi_attribute_fields.html.erb b/app/views/custom_metadata/_fancy_linked_custom_metadata_multi_attribute_fields.html.erb
new file mode 100644
index 0000000000..545850f3a7
--- /dev/null
+++ b/app/views/custom_metadata/_fancy_linked_custom_metadata_multi_attribute_fields.html.erb
@@ -0,0 +1,76 @@
+<% key = attribute.title %>
+<% value ||= [] %>
+
+<% if value.blank? %>
+ <% index = 0 %>
+<% end %>
+
+<% prefix = element_name.split(/\[|\]/).reject(&:empty?).join("_") %>
+
+
+
+ <% if value.blank? %>
+ <%= render partial: 'custom_metadata/single_row', locals: { index: index, value: nil, attribute: attribute, element_name: element_name, element_class: element_class, prefix: prefix } %>
+ <% else %>
+ <% value.each_with_index do |v, idx| %>
+ <% index = idx %>
+ <%= render partial: 'custom_metadata/single_row', locals: { index: index, value: v, attribute: attribute, element_name: element_name, element_class: element_class, prefix: prefix } %>
+ <% end %>
+ <% end %>
+
+
+ <%= button_link_to('Add new', 'add', '#', :id => "add-row-#{prefix}") %>
+
+
+
+
+
+ <%= render partial: 'custom_metadata/single_row', locals: { attribute: attribute, element_name: element_name, element_class: element_class, prefix: prefix } %>
+
+
+
+
diff --git a/app/views/custom_metadata/_single_row.html.erb b/app/views/custom_metadata/_single_row.html.erb
new file mode 100644
index 0000000000..f9474763d7
--- /dev/null
+++ b/app/views/custom_metadata/_single_row.html.erb
@@ -0,0 +1,48 @@
+<% key = attribute.title %>
+<% value ||= nil %>
+<% index ||= 'row-template' %>
+
+<% allow_row_removal = if index == 0
+ attribute.linked_custom_metadata_type.custom_metadata_attributes.none?(&:required?)
+ else
+ true
+ end %>
+<% field_name_prefix = "#{element_name}[#{index}]" %>
+
+
+ <% attribute.linked_custom_metadata_type.custom_metadata_attributes.each do |attr| %>
+
+ <% end %>
+
+
+
+
+
diff --git a/app/views/filtering/_date_filter.html.erb b/app/views/filtering/_date_filter.html.erb
index 247c44130d..bb335adcda 100644
--- a/app/views/filtering/_date_filter.html.erb
+++ b/app/views/filtering/_date_filter.html.erb
@@ -1,61 +1,64 @@
-<% if options.any? %>
- <%
- start_date = nil
- end_date = nil
- # User supplied options (not one of the presets), should not appear as options in the dropdown menu.
- option_pairs = options.select { |o| o.data[:preset] }.map { |option| ["#{option.label} (#{option.count})", option.value] } + [['Custom range', 'custom']]
- active_options = options.select(&:active?)
- selected_option_value = nil
-
- if active_options.any?
- if active_options.length == 1
- active_option = active_options.first
- if active_option.data[:preset]
- selected_option_value = active_option.value
- elsif active_option.data[:date_range].begin.is_a?(Date) # It might be a Time if a custom duration was used (e.g. PT2H), and the field only fits YYYY-MM-DD.
- date_range = active_option.data[:date_range]
- start_date = date_range.begin.iso8601
- end_date = date_range.end.iso8601 unless date_range.end.is_a?(Date::Infinity)
- selected_option_value = 'custom'
- end
- end
- # If the user has used a custom duration, or crafted some complex filter with multiple values,
- # we can't hope to fit it into the date range form, so just add an "Other" option to the dropdown.
- if selected_option_value.nil?
- option_pairs += [['Other', 'other']]
- selected_option_value = 'other'
+<%
+ start_date = nil
+ end_date = nil
+ # User supplied options (not one of the presets), should not appear as options in the dropdown menu.
+ option_pairs = options.select { |o| o.data[:preset] }.map { |option| ["#{option.label} (#{option.count})", option.value] } + [['Custom range', 'custom']]
+ active_options = options.select(&:active?)
+
+ return unless @visible_count > 0 || active_options.any?
+
+ selected_option_value = nil
+
+ if active_options.any?
+ if active_options.length == 1
+ active_option = active_options.first
+ if active_option.data[:preset]
+ selected_option_value = active_option.value
+ elsif active_option.data[:date_range].begin.is_a?(Date) # It might be a Time if a custom duration was used (e.g. PT2H), and the field only fits YYYY-MM-DD.
+ date_range = active_option.data[:date_range]
+ start_date = date_range.begin.iso8601
+ end_date = date_range.end.iso8601 unless date_range.end.is_a?(Date::Infinity)
+ selected_option_value = 'custom'
end
end
- apply_url = url_for({ page: nil, filter: with_filter(key, '_date_', replace: true) }) # We will replace _date_ using JS
- remove_url = url_for({ page: nil, filter: without_filter(key) })
- %>
+ # If the user has used a custom duration, or crafted some complex filter with multiple values,
+ # we can't hope to fit it into the date range form, so just add an "Other" option to the dropdown.
+ if selected_option_value.nil?
+ option_pairs += [['Other', 'other']]
+ selected_option_value = 'other'
+ end
+ end
+
+ apply_url = url_for({ page: nil, filter: with_filter(key, '_date_', replace: true) }) # We will replace _date_ using JS
+ remove_url = url_for({ page: nil, filter: without_filter(key) })
+%>
- <%= content_tag(:div, class: 'filter-category', data: { 'filter-category' => key.to_s,
- role: 'seek-date-filter',
- 'apply-filter-url' => apply_url,
- 'remove-filter-url' => remove_url }) do %>
- <%= t(key, default: key.to_s).titleize %>
- <%= select_tag(nil,
- options_for_select(option_pairs, selected_option_value),
- data: { role: 'seek-date-filter-select' },
- autocomplete: 'off',
- include_blank: 'Any time',
- class: 'filter-option-dropdown')
- %>
- <%= content_tag(:div, { class: 'filter-option-field-group', style: 'border-top: 1px solid #ccc;', data: { role: 'seek-date-filter-custom' } }) do %>
- <%= text_field_tag(nil, start_date,
- data: { role: 'seek-date-filter-period-start' },
- placeholder: 'Start',
- autocomplete: 'off',
- class: 'filter-option-field') -%>
- <%= text_field_tag(nil, end_date,
- data: { role: 'seek-date-filter-period-end' },
- placeholder: 'End (optional)',
- autocomplete: 'off',
- class: 'filter-option-field') -%>
- <%= link_to('Go', '#', data: { role: 'seek-date-filter-btn' }, class: 'filter-option-field-button') %>
- <% end %>
+<%= content_tag(:div, class: 'filter-category', data: { 'filter-category' => key.to_s,
+ role: 'seek-date-filter',
+ 'apply-filter-url' => apply_url,
+ 'remove-filter-url' => remove_url }) do %>
+ <%= t(key, default: key.to_s).titleize %>
+ <%= select_tag(nil,
+ options_for_select(option_pairs, selected_option_value),
+ data: { role: 'seek-date-filter-select' },
+ autocomplete: 'off',
+ include_blank: 'Any time',
+ class: 'filter-option-dropdown')
+ %>
+ <%= content_tag(:div, { class: 'filter-option-field-group', style: 'border-top: 1px solid #ccc;', data: { role: 'seek-date-filter-custom' } }) do %>
+ <%= text_field_tag(nil, start_date,
+ data: { role: 'seek-date-filter-period-start' },
+ placeholder: 'Start',
+ autocomplete: 'off',
+ class: 'filter-option-field') -%>
+ <%= text_field_tag(nil, end_date,
+ data: { role: 'seek-date-filter-period-end' },
+ placeholder: 'End (optional)',
+ autocomplete: 'off',
+ class: 'filter-option-field') -%>
+ <%= link_to('Go', '#', data: { role: 'seek-date-filter-btn' }, class: 'filter-option-field-button') %>
<% end %>
<% end %>
+
diff --git a/app/views/general/_index.html.erb b/app/views/general/_index.html.erb
index 574ef2ffc1..37f9ff69e2 100644
--- a/app/views/general/_index.html.erb
+++ b/app/views/general/_index.html.erb
@@ -5,10 +5,14 @@
show_new_button = true unless local_assigns.has_key?(:show_new_button)
title ||= nil
subtitle ||= nil
+ isa_templates_enabled = Seek::Config.sample_type_template_enabled && Seek::Config.project_single_page_advanced_enabled
%>
<% if show_new_button && controller_model.can_create? %>
+ <% if isa_templates_enabled %>
+ <%= link_to "Query by #{t('template').pluralize}", query_form_samples_path, class: "btn btn-default btn" %>
+ <% end %>
<%= button_link_to(new_item_label, "new", new_item_path) %>
<% end %>
diff --git a/app/views/general/_split_button_checkbox.html.erb b/app/views/general/_split_button_checkbox.html.erb
deleted file mode 100644
index fbf98b52f3..0000000000
--- a/app/views/general/_split_button_checkbox.html.erb
+++ /dev/null
@@ -1,50 +0,0 @@
-<%
- #<%= render :partial => 'general/split_button_checkbox',
- #locals: { checkbox_id: publishing_item_param(item),
- # checkbox_class: "#{item.class.name}_#{item.id}",
- # published: true,
- # checkbox_text: "Publish?",
- # checked: checked,
- # toggle: children.any?,
- # cb_parent_selector: "div\##{checkbox_class}.split_button_parent" } - % >
-
- checkbox_class ||= "no_name" # <- Needed!
- checkbox_id ||= checkbox_class
- published ||= false
- checkbox_text ||= ""
- checked ||= false
- toggle ||= false
- cb_parent_selector ||= "div\##{checkbox_class}.split_button_parent"
--%>
-
-
- <% if published %>
-
-
- Published
-
- <% else %>
-
- <%= check_box_tag checkbox_id, 1, checked,
- {:class=>checkbox_class,
- :onclick=>"checkRepeatedItems(this)"} -%>
- <%= checkbox_text -%>
-
- <% end %>
-
- <% if toggle %>
-
-
- Toggle Dropdown
-
-
- <% end %>
-
diff --git a/app/views/isa_assays/_assay_samples.html.erb b/app/views/isa_assays/_assay_samples.html.erb
index 071779286b..42f336c3b9 100644
--- a/app/views/isa_assays/_assay_samples.html.erb
+++ b/app/views/isa_assays/_assay_samples.html.erb
@@ -1,6 +1,9 @@
-<% assay ||= nil %>
-<% valid_assay = assay&.sample_type.present? %>
-<% sample_type = assay&.sample_type %>
+<%
+ assay ||= nil
+ valid_assay = assay&.sample_type.present?
+ sample_type = assay&.sample_type
+ project = assay&.projects&.first
+%>
-<%= render partial: 'isa_studies/buttons' %>
+<%= render partial: 'isa_studies/buttons', locals: {uploadExcel: "assaySampleUploadExcel()", sample_type_id: sample_type&.id} %>
<% if valid_assay %>
<% end %>
diff --git a/app/views/isa_studies/_buttons.html.erb b/app/views/isa_studies/_buttons.html.erb
index a17d0ccfc3..47466814c3 100644
--- a/app/views/isa_studies/_buttons.html.erb
+++ b/app/views/isa_studies/_buttons.html.erb
@@ -6,6 +6,7 @@ delete||="SampleSetAsDeleted()"
save||="SampleSave()"
permissions||="loadBatchPermission('sampleDynamicTable',this)"
exportToExcel||="sampleExportExcel()"
+uploadExcel||="studySampleUploadExcel()"
%>
@@ -17,14 +18,32 @@ exportToExcel||="sampleExportExcel()"
>Save
+
+
Upload excel spreadsheet:
+
+
+
diff --git a/app/views/isa_studies/_source_material.html.erb b/app/views/isa_studies/_source_material.html.erb
index 63766ee298..4d43e14d5e 100644
--- a/app/views/isa_studies/_source_material.html.erb
+++ b/app/views/isa_studies/_source_material.html.erb
@@ -1,5 +1,8 @@
-<% study ||= nil %>
-<% sample_type = study&.sample_types&.first %>
+<%
+ study ||= nil
+ sample_type = study&.sample_types&.first
+ project = study&.projects&.first
+%>
@@ -11,7 +14,8 @@
<%= render partial: 'isa_studies/buttons', locals:{ add_row: "SourceAddNewRow()", paste_cb:
"SourcePasteFromClipboard()", delete: "SourceSetAsDeleted()", save: "SourceSave()",
-permissions: "loadBatchPermission('sourceDynamicTable',this)", exportToExcel: "sourceExportExcel()" } %>
+permissions: "loadBatchPermission('sourceDynamicTable',this)", exportToExcel: "sourceExportExcel()",
+uploadExcel: 'sourceUploadExcel()', sample_type_id: sample_type&.id} %>
<% if sample_type %>
<% end %>
diff --git a/app/views/isa_studies/_study_samples.html.erb b/app/views/isa_studies/_study_samples.html.erb
index 46bfad6614..57b7ff0b13 100644
--- a/app/views/isa_studies/_study_samples.html.erb
+++ b/app/views/isa_studies/_study_samples.html.erb
@@ -1,5 +1,8 @@
-<% study ||= nil %>
-<% sample_type = study&.sample_types&.second %>
+<%
+ study ||= nil
+ sample_type = study&.sample_types&.second
+ project = study&.projects&.first
+%>
-<%= render partial: 'isa_studies/buttons' %>
+<%= render partial: 'isa_studies/buttons', locals: {uploadExcel: "studySampleUploadExcel()", sample_type_id: sample_type&.id} %>
<% if sample_type %>
<% end %>
diff --git a/app/views/people/_buttons.html.erb b/app/views/people/_buttons.html.erb
index 59e0864aa2..bd48f3beff 100644
--- a/app/views/people/_buttons.html.erb
+++ b/app/views/people/_buttons.html.erb
@@ -1,15 +1,15 @@
<% if mine?(@person) -%>
- <% tooltip_text_sharing = "You can change the sharing policy and permissions for your assets in batch. A preview of selected assets will be given before you choose new permissions for them." %>
- <% tooltip_text_publishing = "Publish your owned assets in one click. A preview will be given before publishing" %>
- <%= button_link_to "Batch permission changes", "publish", batch_sharing_permission_preview_person_path(@person), 'data-tooltip' => tooltip(tooltip_text_sharing) -%>
- <%= button_link_to "Publish your assets", "publish", batch_publishing_preview_person_path(@person), 'data-tooltip' => tooltip(tooltip_text_publishing) -%>
+ <% tooltip_text_sharing = "You can change the sharing policy and permissions for your items in batch. A preview of selected items will be given before you choose new permissions for them." %>
+ <% tooltip_text_publishing = "Publish your owned items in one click. A preview will be given before publishing" %>
+ <%= button_link_to "Batch permission changes", "publish", batch_sharing_permission_preview_person_path(@person), 'data-tooltip': tooltip(tooltip_text_sharing) -%>
+ <%= button_link_to "Publish your items", "publish", batch_publishing_preview_person_path(@person), 'data-tooltip': tooltip(tooltip_text_publishing) -%>
<% if @person.is_in_any_gatekept_projects? %>
<%= button_link_to "Assets awaiting approval", "waiting", waiting_approval_assets_person_path(@person),
- 'data-tooltip' => tooltip("The assets you have requested to publish, but are awaiting the #{t('asset_gatekeeper').downcase} approval") -%>
+ 'data-tooltip': tooltip("The assets you have requested to publish, but are awaiting the #{t('asset_gatekeeper').downcase} approval") -%>
<% end %>
<% if @person.is_asset_gatekeeper_of_any_project? %>
<%= button_link_to "Assets you are Gatekeeping", "waiting", requested_approval_assets_person_path(@person),
- 'data-tooltip' => tooltip("The assets people have requested to publish, but are still awaiting your approval") -%>
+ 'data-tooltip': tooltip("The assets people have requested to publish, but are still awaiting your approval") -%>
<% end %>
<% end %>
@@ -20,7 +20,7 @@
<% if mine?(@person) -%>
- <%= image_tag_for_key "lock", url_for({:controller=>:users, :action=>:edit, :id=>@person.user}), "Manage Account", nil, "Manage Account" -%>
+ <%= image_tag_for_key "lock", url_for({controller: :users, action: :edit, id: @person.user}), "Manage Account", nil, "Manage Account" -%>
<% if Seek::Config.omniauth_enabled %>
@@ -45,7 +45,7 @@
<% if admin_logged_in? -%>
- <%= image_tag_for_key "destroy", person_path(@person), "Delete Person", { data: { confirm: 'Are you sure?' }, :method => :delete}, "Delete Person" -%>
+ <%= image_tag_for_key "destroy", person_path(@person), "Delete Person", { data: { confirm: 'Are you sure?' }, method: :delete}, "Delete Person" -%>
<% end -%>
<% end %>
diff --git a/app/views/programmes/activation_review.html.erb b/app/views/programmes/activation_review.html.erb
index b7562f03b1..d373da2cd8 100644
--- a/app/views/programmes/activation_review.html.erb
+++ b/app/views/programmes/activation_review.html.erb
@@ -1,4 +1,4 @@
-<%= render :partial => "general/item_title",:locals => {:item=>@programme, :title_prefix=>"Acitivation required for: "} %>
+<%= render :partial => "general/item_title",:locals => {:item=>@programme, :title_prefix=>"Activation required for: "} %>
A <%= t('programme') %> has been created by a user, and requires activation. The <%= t('programme') %> created is <%= link_to @programme.title, @programme %>.
diff --git a/app/views/projects/_project_selector.html.erb b/app/views/projects/_project_selector.html.erb
index e0585fc7bf..b89c0dc3bd 100644
--- a/app/views/projects/_project_selector.html.erb
+++ b/app/views/projects/_project_selector.html.erb
@@ -30,7 +30,7 @@
title = t('project').pluralize
title += '* '.html_safe unless allow_nil
- object_type_text = resource.class.name.underscore.humanize
+ object_type_text = text_for_resource(resource)
%>
<%= folding_panel(title, false, id: "add_projects_form",
@@ -106,8 +106,7 @@
var licenseSelect = $j('#license-select');
if (licenseSelect.length && licenseSelect.data('canOverwrite') &&
$j('option[value="'+Sharing.defaultLicenses[project.id]+'"]', licenseSelect).length) {
- licenseSelect.val(Sharing.defaultLicenses[project.id]);
- zenodoExport.setLicenseUrl();
+ licenseSelect.val(Sharing.defaultLicenses[project.id]).change();
}
}
this.possibilities.splice(i, 1);
diff --git a/app/views/sample_types/_sample_attribute_form.html.erb b/app/views/sample_types/_sample_attribute_form.html.erb
index 3ccdf54405..4f01e78e1a 100644
--- a/app/views/sample_types/_sample_attribute_form.html.erb
+++ b/app/views/sample_types/_sample_attribute_form.html.erb
@@ -87,6 +87,7 @@
grouped_options_for_select(options,
link_to_self ? 'self' : linked_sample_type_id),
include_blank: true,
+ disabled: !allow_type_change,
class: 'form-control linked-sample-type-selection' %>
diff --git a/app/views/samples/show.html.erb b/app/views/samples/show.html.erb
index 04be5e5e2d..bd0b8f148c 100644
--- a/app/views/samples/show.html.erb
+++ b/app/views/samples/show.html.erb
@@ -20,6 +20,12 @@
Source data:
<%= link_to @sample.originating_data_file.title, @sample.originating_data_file %>
+ <% if @sample.edit_count.positive? %>
+
+ No longer valid
+
+ <% end %>
<% end %>
<%= render :partial => "attribute_values", :locals => { :sample => @sample } %>
diff --git a/app/views/sharing/_batch_change_results.html.erb b/app/views/sharing/_batch_change_results.html.erb
new file mode 100644
index 0000000000..8ba1c01693
--- /dev/null
+++ b/app/views/sharing/_batch_change_results.html.erb
@@ -0,0 +1,36 @@
+<% return unless @items_for_sharing %>
+<% items_text = 'item'.pluralize(@items_for_sharing.size) %>
+<% if @success&.any? || @gatekeeper_required&.any? %>
+
+ <% if @success.any? %>
+ The sharing policies for your selected <%= items_text -%> were successfully updated:
+
+ <% @success.each do |item| %>
+ <%= item.title %>
+ <% end %>
+
+ <% end %>
+
+ <% if @gatekeeper_required.any? %>
+ Publishing the following <%= items_text -%> requires approval from a gatekeeper:
+
+ <% @gatekeeper_required.each do |item| %>
+ <%= item.title %>
+ <% end %>
+
+ The <%= items_text -%> will not be published until approved.
+ <% end %>
+
+<% elsif @error&.any? %>
+
+ The sharing policies for your selected <%= items_text -%> were not successfully updated:
+
+ <% @error.each do |item| %>
+
+ <%= item.title %>
+ The reason: <%= item.errors.full_messages.join(', ') %>
+
+ <% end %>
+
+
+<% end %>
diff --git a/app/views/single_pages/_duplicate_samples_panel.html.erb b/app/views/single_pages/_duplicate_samples_panel.html.erb
new file mode 100644
index 0000000000..3e7696e7a5
--- /dev/null
+++ b/app/views/single_pages/_duplicate_samples_panel.html.erb
@@ -0,0 +1,51 @@
+<% unless @possible_duplicates.nil? or @possible_duplicates.compact.none? %>
+ <%= folding_panel("Possible Duplicates
#{@possible_duplicates.size} ", true, :id => "duplicate-samples-panel", :body_options => {:id => "duplicate-samples-panel-content"},
+ :help_text => "These new samples have been matched to already existing samples.") do %>
+
+
+
+
+ <% for key in @possible_duplicates[0].keys %>
+ <% unless %w[uuid duplicate].include?(key) %>
+ <%= key %>
+ <% end %>
+ <% end %>
+
+ <% for dupl_sample in @possible_duplicates %>
+ ' >
+ class="btn glyphicon glyphicon-trash danger" style="background-color:#d9534f;color:white;" onclick=<%= "removeSample('duplicate-sample-#{dupl_sample['duplicate']['id']}')" %>>
+ <% dupl_sample.map do |key, val| %>
+ <% val = '' if key =='id' %>
+ <% unless %w[uuid duplicate].include?(key) %>
+ <% if @multiple_input_fields.include?(key)%>
+
+ <% val.each do |sub_sample| %>
+ '><%= sub_sample['title'] %>
+ <% end %>
+
+ <% else %>
+ ' ><%= val %>
+ <% end %>
+ <% end %>
+ <% end %>
+ ' class="danger">
+ <% dupl_sample['duplicate'].map do |key, val| %>
+ <% unless %w[uuid duplicate].include?(key) %>
+ <% if @multiple_input_fields.include?(key)%>
+
+ <% val.each do |sub_sample| %>
+ '><%= sub_sample['title'] %>
+ <% end %>
+
+ <% else %>
+ <%= val%>
+ <% end %>
+ <% end %>
+ <% end %>
+
+
+ <% end %>
+
+
+ <% end %>
+<% end %>
diff --git a/app/views/single_pages/_general_panel.html.erb b/app/views/single_pages/_general_panel.html.erb
new file mode 100644
index 0000000000..6880ad7eaf
--- /dev/null
+++ b/app/views/single_pages/_general_panel.html.erb
@@ -0,0 +1,29 @@
+<%= folding_panel("General Information", true, :id => "general-information-panel",
+:help_text => "This pane contains an overview of the permissions needed to upload.") do %>
+ <% [@project, @study, @assay]. map do | asset | %>
+ <% next if asset.nil? %>
+ <% asset_name = asset.class.to_s.singularize %>
+
<%= asset_name %>
+
ID: <%= asset.id%>
+
UUID: <%= asset.uuid %>
+
Title: <%= asset.title %>
+ <% if asset_name == "Project"%>
+ <% if current_user.person.member_of?(asset)%>
+
<%= current_user.person.name %> is member of this project:
+ <% else %>
+
<%= current_user.person.name %> is member of this project:
+ <% can_upload = false %>
+ <% errors.append("You must be a member of this project!") %>
+ <% end %>
+ <% else %>
+ <% if asset.can_view?%>
+
<%= current_user.person.name %> can view:
+ <% else %>
+
<%= current_user.person.name %> can view:
+ <% can_upload = false %>
+ <% errors.append("You must have at least viewing permission for the #{asset_name} '#{asset.title}'.") %>
+ <% end %>
+ <% end %>
+
+ <% end %>
+<% end %>
diff --git a/app/views/single_pages/_new_samples_panel.html.erb b/app/views/single_pages/_new_samples_panel.html.erb
new file mode 100644
index 0000000000..cf157efaa2
--- /dev/null
+++ b/app/views/single_pages/_new_samples_panel.html.erb
@@ -0,0 +1,37 @@
+<% unless @new_samples.nil? or @new_samples.compact.none? %>
+ <%= folding_panel("New Samples
#{@new_samples.size} ", true, :id => "new-samples-panel", :body_options => {:id => "new-samples-panel-content"},
+ :help_text => "These samples have been detected as new samples and will be created.") do %>
+
+
+
+
+ <% for key in @new_samples[0].keys %>
+ <% unless key == 'uuid' %>
+ <%= key %>
+ <% end %>
+ <% end %>
+
+ <% for new_sample in @new_samples %>
+ <% new_sample_id = UUID.generate %>
+
+ class="btn glyphicon glyphicon-trash danger" style="background-color:#d9534f;color:white;" onclick=<%= "removeSample('new-sample-#{new_sample_id}')" %>>
+ <% new_sample.map do |key, val| %>
+ <% val = '' if key =='id' %>
+ <% unless key == 'uuid' %>
+ <% if @multiple_input_fields.include?(key)%>
+
+ <% val.each do |sub_sample| %>
+ '><%= sub_sample['title'] %>
+ <% end %>
+
+ <% else %>
+ <%= val %>
+ <% end %>
+ <% end %>
+ <% end %>
+
+ <% end %>
+
+
+ <% end %>
+<% end %>
diff --git a/app/views/single_pages/_unauthorized_samples_panel.html.erb b/app/views/single_pages/_unauthorized_samples_panel.html.erb
new file mode 100644
index 0000000000..8ad35705d2
--- /dev/null
+++ b/app/views/single_pages/_unauthorized_samples_panel.html.erb
@@ -0,0 +1,40 @@
+<% unless @unauthorized_samples.nil? or @unauthorized_samples.compact.none? %>
+ <% @can_upload = false %>
+ <% errors.append("There are unauthorized samples present in the spreadsheet.") %>
+ <%= folding_panel("Unauthorized Samples", false, :id => "unauthorized-samples-panel", :body_options => {:id => "unauthorized-samples-panel-content"},
+ :help_text => "Sample the current user does not have permission to edit them.") do %>
+
+
+ You don't have permission to edit the samples listed below. Please contact the submitter of these samples or revert the changes in the spreadsheet to its original values.
+
+
+
+
+
+ <% for key in @unauthorized_samples[0].keys %>
+ <% unless key == 'uuid' %>
+ <%= key %>
+ <% end %>
+ <% end %>
+
+ <% for unauthorized_sample in @unauthorized_samples %>
+ ' class="">
+ <% unauthorized_sample.map do |key, val| %>
+ <% unless key == 'uuid' %>
+ <% if @multiple_input_fields.include?(key) %>
+
+ <% val.each do |sub_sample| %>
+ '><%= sub_sample['title'] %>
+ <% end %>
+
+ <% else %>
+ <%= val %>
+ <% end %>
+ <% end %>
+ <% end %>
+
+ <% end %>
+
+
+ <% end %>
+<% end %>
diff --git a/app/views/single_pages/_update_samples_panel.html.erb b/app/views/single_pages/_update_samples_panel.html.erb
new file mode 100644
index 0000000000..b2de42c349
--- /dev/null
+++ b/app/views/single_pages/_update_samples_panel.html.erb
@@ -0,0 +1,51 @@
+<% unless @update_samples.nil? or @update_samples.compact.none? %>
+ <%= folding_panel("Samples to Update
#{@update_samples.size} ", true, :id => "existing-samples-panel", :body_options => {:id => "existing-samples-panel-content"},
+ :help_text => "These samples were detected existing samples and will be updated.") do %>
+
+
+
+
+ <% for key in @update_samples[0].keys %>
+ <% unless key == 'uuid' %>
+ <%= key %>
+ <% end %>
+ <% end %>
+
+ <% for update_sample in @update_samples %>
+ ' >
+ <% db_sample = @authorized_db_samples.select { |s| s['id'] == update_sample['id'] }.first %>
+ class="btn glyphicon glyphicon-trash danger" style="background-color:#d9534f;color:white;" onclick=<%= "removeSample('update-sample-#{update_sample['id']}')" %>>
+ <% update_sample.map do |key, val| %>
+ <% unless key == 'uuid' %>
+ <% if @multiple_input_fields.include?(key)%>
+ ' >
+ <% val.each do |sub_sample| %>
+ '><%= sub_sample['title'] %>
+ <% end %>
+
+ <% else %>
+ ' ><%= val %>
+ <% end %>
+ <% end %>
+ <% end %>
+
+ ' >
+ <% db_sample.map do |key, val| %>
+ <% unless key == 'uuid' %>
+ <% if @multiple_input_fields.include?(key)%>
+
+ <% val.each do |sub_sample| %>
+ '><%= sub_sample['title'] %>
+ <% end %>
+
+ <% else %>
+ <%= val %>
+ <% end %>
+ <% end %>
+ <% end %>
+
+ <% end %>
+
+
+ <% end %>
+<% end %>
diff --git a/app/views/single_pages/download_samples_excel.axlsx b/app/views/single_pages/download_samples_excel.axlsx
index 82b8837615..800b4a4d09 100644
--- a/app/views/single_pages/download_samples_excel.axlsx
+++ b/app/views/single_pages/download_samples_excel.axlsx
@@ -41,12 +41,6 @@ workbook.add_worksheet(name: 'Metadata') do |sheet|
sheet.add_row ['Fairdom ID:', @study.id]
sheet.add_row ['UUID:', @study.uuid]
- if @assay
- sheet.add_row ['Assay:'], style: title_style
- sheet.add_row ['Fairdom ID:', @assay.id]
- sheet.add_row ['UUID:', @assay.uuid]
- end
-
sheet.add_row ['Sample Type:'], style: title_style
sheet.add_row ['Fairdom ID:', @sample_type.id]
sheet.add_row ['UUID:', @sample_type.uuid]
@@ -55,6 +49,12 @@ workbook.add_worksheet(name: 'Metadata') do |sheet|
sheet.add_row ['Fairdom ID:', @template.id]
sheet.add_row ['UUID:', @template.uuid]
+ if @assay
+ sheet.add_row ['Assay:'], style: title_style
+ sheet.add_row ['Fairdom ID:', @assay.id]
+ sheet.add_row ['UUID:', @assay.uuid]
+ end
+
sheet.sheet_protection.password = secret_pwd
end
diff --git a/app/views/single_pages/sample_batch_sharing_permission_preview.html.erb b/app/views/single_pages/sample_batch_sharing_permission_preview.html.erb
deleted file mode 100644
index dfca54e6ce..0000000000
--- a/app/views/single_pages/sample_batch_sharing_permission_preview.html.erb
+++ /dev/null
@@ -1,227 +0,0 @@
-<%
- sample_ids = (params[:sample_ids] || []).map(&:to_i)
-
- items_not_in_isa_hash = SharingPermissionsHelper::ITEMS_NOT_IN_ISA_HASH
- items_not_in_isa_hash[:children] =[]
-
- samples = Sample.where(id: sample_ids).order(:title).authorized_for('manage', User.current_user).to_a
- all_related_items_hash = { 'Sample' => { items: samples }}
-
- items_not_in_isa = filter_items_not_in_ISA(all_related_items_hash)
-
- @policy_params = params[:policy_attributes]
-
- flash_exists = flash[:error] || flash[:notice]
-%>
-
-<% if !flash_exists %>
- <%= show_title "Change permission of #{t('sample').pluralize}" -%>
-<% end %>
-
-
-<%= form_tag({:action => :batch_change_permission_for_selected_items}, :method => :post, id: "change-permission-preview-form") do -%>
-
- <% if !sample_ids.any? %>
-
-
- <% unless flash_exists %>
- No sample has been selected...
- <% end %>
-
-
- <% end %>
- <% if flash_exists %>
-
alert-dismissable" role="alert">
- <% if flash[:notice] %>
- <%= flash[:notice]%>
- <% else%>
- <%= flash[:error]%>
- <% end %>
-
- <% end %>
-
- <% if !flash_exists %>
-
- <%= folding_panel("Samples", false, :id => 'not_isa_item', :body_options => {:id => 'items_fold_content'},
- :help_text => nil) do %>
-
-
<%= link_to "Select All", "#", id: "select_all_not_isa" -%> |
-
<%= link_to "Deselect All", "#", id: "deselect_all_not_isa" -%> |
-
<%= link_to "Expand All", "#", id: "expand_all_not_isa" -%> |
-
<%= link_to "Collapse All", "#", id: "collapse_all_not_isa" -%>
-
- <% items_not_in_isa.each do |resource_type, resource_items| %>
- <% asset_node= asset_node_json(resource_type, resource_items) %>
- <% items_not_in_isa_hash[:children].append(asset_node) %>
- <% end %>
-
-
-
- <% end %>
-
- <% end %>
-
-
- <% if !flash_exists %>
-
- <%= submit_tag "Next", data: {disable_with: 'Next'}, :class => 'btn btn-primary', onclick: "submitBatchPermissionPreviewForm()" -%>
- or
- <%= cancel_button(@asset, { id: "cancel-batch-permission-preview" }) %>
-
- <% end -%>
-
-
-
-<% end -%>
-
-
-
-
diff --git a/app/views/single_pages/sample_batch_sharing_permissions_changed.html.erb b/app/views/single_pages/sample_batch_sharing_permissions_changed.html.erb
new file mode 100644
index 0000000000..0872607cfd
--- /dev/null
+++ b/app/views/single_pages/sample_batch_sharing_permissions_changed.html.erb
@@ -0,0 +1,3 @@
+<%= render partial: 'sharing/batch_change_results' %>
+
+
OK
diff --git a/app/views/single_pages/sample_sharing_bulk_change_preview.html.erb b/app/views/single_pages/sample_sharing_bulk_change_preview.html.erb
index a116949d03..c0f86b7e72 100644
--- a/app/views/single_pages/sample_sharing_bulk_change_preview.html.erb
+++ b/app/views/single_pages/sample_sharing_bulk_change_preview.html.erb
@@ -14,7 +14,7 @@
<% @items_for_sharing.each do |item| %>
- <%= hidden_field_tag sharing_item_param(item), 1 %>
+ <%= hidden_field_tag publishing_item_param(item), 1 %>
<%= text_for_resource item -%>: <%= link_to item.title, item -%>
<% if item.try(:is_downloadable?) %>
diff --git a/app/views/single_pages/sample_upload_content.html.erb b/app/views/single_pages/sample_upload_content.html.erb
new file mode 100644
index 0000000000..28728d8dd6
--- /dev/null
+++ b/app/views/single_pages/sample_upload_content.html.erb
@@ -0,0 +1,211 @@
+<%
+ def any_samples_to_upload?
+ !((@new_samples.nil? or @new_samples.compact.none?) and (@update_samples.nil? or @update_samples.compact.none?) and (@possible_duplicates.nil? or @possible_duplicates.compact.none?))
+ end
+ errors = []
+%>
+
+<% @can_upload = true %>
+
+
+ <%# General information panel %>
+ <%= render partial: 'general_panel' %>
+
+ <%# New Samples panel %>
+ <%= render partial: 'new_samples_panel' %>
+
+ <%# Update Samples panel %>
+ <%= render partial: 'update_samples_panel' %>
+
+ <%# Possible Duplicate Samples panel %>
+ <%= render partial: 'duplicate_samples_panel' %>
+
+ <%# Panel for Sample with wrong permissions %>
+ <%= render partial: 'unauthorized_samples_panel' %>
+
+
+ <% unless @can_upload %>
+
+
×
+
Permissions conflict
+
Unable to upload the current set of samples!
+
Please expand the 'General Information' and/or 'Unauthorized Samples' pane for more information.
+
Correct the following errors:
+
+ <% for error in errors %>
+ <%= error %>
+ <% end %>
+
+
+ <% end %>
+
+ <% if (@can_upload and !any_samples_to_upload?) %>
+
+
×
+
No changes detected
+
The provided spreadsheet did not include any new samples or changes to already existing ones!
+
Please click the cancel button to dismiss this window.
+
+ <% end %>
+
+ <%= submit_tag "Upload", data: {disable_with: 'Uploading ...'}, :class => 'btn btn-primary', onclick: "submitUpload()" if (@can_upload and any_samples_to_upload?)%>
+ <%= submit_tag "Cancel", data: {id: 'cancelModalUploadExcel'}, :class => 'btn btn-secondary', onclick: "closeModalForm()" %>
+ <%= image_tag('ajax-loader.gif', id: 'sample-upload-spinner', style: 'display: none') %>
+
+
+
diff --git a/app/views/single_pages/show.html.erb b/app/views/single_pages/show.html.erb
index 327d96e652..10a1dd58a3 100644
--- a/app/views/single_pages/show.html.erb
+++ b/app/views/single_pages/show.html.erb
@@ -48,7 +48,7 @@
<%= modal(id: 'change-batch-permission-modal', size: 'xl') do %>
- <%= modal_header("Change permission") %>
+ <%= modal_header("Batch permission changes") %>
<%= modal_body do %>
hello
@@ -56,6 +56,13 @@
<% end %>
<% end %>
+ <%= modal(id: 'upload-excel-modal', size: 'xl') do %>
+ <%= modal_header("Upload from spreadsheet") %>
+ <%= modal_body do %>
+
...
+ <% end %>
+ <% end %>
+
diff --git a/config/initializers/seek_configuration.rb b/config/initializers/seek_configuration.rb
index 5891ffa215..35d0b8588e 100644
--- a/config/initializers/seek_configuration.rb
+++ b/config/initializers/seek_configuration.rb
@@ -257,6 +257,7 @@ def load_seek_config_defaults!
Seek::Config.default :life_monitor_enabled, false
Seek::Config.default :life_monitor_url, 'https://api.lifemonitor.eu/'
+ Seek::Config.default :life_monitor_ui_url, 'https://app.lifemonitor.eu/'
Seek::Config.default :git_support_enabled, false
Seek::Config.default :bio_tools_enabled, false
diff --git a/config/routes.rb b/config/routes.rb
index fc9402d1db..4a51ba1e9a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -758,6 +758,7 @@
post :batch_sharing_permission_changed
post :export_to_excel, action: :export_to_excel
get :download_samples_excel, action: :download_samples_excel
+ post :upload_samples, action: :upload_samples
end
end
diff --git a/config/schedule.rb b/config/schedule.rb
index 5216b0f962..743d0d60ed 100644
--- a/config/schedule.rb
+++ b/config/schedule.rb
@@ -71,6 +71,11 @@ def offset(off_hours)
runner "Seek::BioSchema::DataDump.generate_dumps"
end
+# Generate a new sitemap...
+every 1.day, at: '12:45 am' do
+ rake "-s sitemap:refresh"
+end
+
# not safe to automatically add in a non containerised environment
if Seek::Docker.using_docker?
every 10.minutes do
diff --git a/config/sitemap.rb b/config/sitemap.rb
new file mode 100644
index 0000000000..90cfab2813
--- /dev/null
+++ b/config/sitemap.rb
@@ -0,0 +1,19 @@
+# https://github.com/kjvarga/sitemap_generator#sitemapgenerator
+SitemapGenerator::Sitemap.sitemaps_path = "sitemaps"
+SitemapGenerator::Sitemap.create_index = "auto"
+SitemapGenerator::Sitemap.compress = false
+SitemapGenerator::Sitemap.default_host = URI.parse(Seek::Config.site_base_url)
+
+SitemapGenerator::Sitemap.create do
+ Seek::Util.searchable_types.each do |type|
+ add polymorphic_path(type), lastmod: type.maximum(:updated_at), changefreq: 'daily', priority: 0.7
+ end
+end
+
+Seek::Util.searchable_types.each do |type|
+ SitemapGenerator::Sitemap.create(filename: type.table_name, include_root: false) do
+ type.authorized_for('view', nil).find_all do |obj|
+ add polymorphic_path(obj), lastmod: obj.updated_at, changefreq: 'daily', priority: 0.7
+ end
+ end
+end
diff --git a/db/migrate/20230809054421_remove_custom_metadata_resource_link.rb b/db/migrate/20230809054421_remove_custom_metadata_resource_link.rb
new file mode 100644
index 0000000000..55aea48193
--- /dev/null
+++ b/db/migrate/20230809054421_remove_custom_metadata_resource_link.rb
@@ -0,0 +1,12 @@
+class RemoveCustomMetadataResourceLink < ActiveRecord::Migration[6.1]
+ def up
+ drop_table :custom_metadata_resource_links
+ end
+
+ def down
+ create_table :custom_metadata_resource_links do |t|
+ t.references :custom_metadata
+ t.references :resource, polymorphic: true
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 20e2c78dbd..ca3422774a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -389,14 +389,6 @@
t.index ["sample_controlled_vocab_id"], name: "index_custom_metadata_attributes_on_sample_controlled_vocab_id"
end
- create_table "custom_metadata_resource_links", force: :cascade do |t|
- t.bigint "custom_metadata_id"
- t.string "resource_type"
- t.bigint "resource_id"
- t.index ["custom_metadata_id"], name: "index_custom_metadata_resource_links_on_custom_metadata_id"
- t.index ["resource_type", "resource_id"], name: "index_custom_metadata_resource_links_on_resource"
- end
-
create_table "custom_metadata_types", force: :cascade do |t|
t.string "title"
t.integer "contributor_id"
diff --git a/db/seeds/007_sample_attribute_types.seeds.rb b/db/seeds/007_sample_attribute_types.seeds.rb
index 5507134ace..094c3a19eb 100644
--- a/db/seeds/007_sample_attribute_types.seeds.rb
+++ b/db/seeds/007_sample_attribute_types.seeds.rb
@@ -88,6 +88,9 @@
linked_custom_metadata_type = SampleAttributeType.find_or_initialize_by(title:'Linked Custom Metadata')
linked_custom_metadata_type.update(base_type: Seek::Samples::BaseType::LINKED_CUSTOM_METADATA)
+linked_custom_metadata_multi_type = SampleAttributeType.find_or_initialize_by(title:'Linked Custom Metadata (multiple)')
+linked_custom_metadata_multi_type.update(base_type: Seek::Samples::BaseType::LINKED_CUSTOM_METADATA_MULTI)
+
puts "Seeded #{SampleAttributeType.count - count} sample attribute types"
# Sample types
diff --git a/lib/life_monitor/rest/client.rb b/lib/life_monitor/rest/client.rb
index 8f99e884ba..dfb7325803 100644
--- a/lib/life_monitor/rest/client.rb
+++ b/lib/life_monitor/rest/client.rb
@@ -55,10 +55,6 @@ def list_workflows
perform("/registries/current/workflows?status=true&versions=true", :get, content_type: :json)
end
- def self.status_page_url(workflow, base: Seek::Config.life_monitor_url)
- URI.join(base, "/workflow;uuid=#{workflow.uuid}").to_s
- end
-
private
def perform(path, method, opts = {})
diff --git a/lib/seek/assets_standard_controller_actions.rb b/lib/seek/assets_standard_controller_actions.rb
index 0f5e07c7a0..60febb16a9 100644
--- a/lib/seek/assets_standard_controller_actions.rb
+++ b/lib/seek/assets_standard_controller_actions.rb
@@ -155,17 +155,6 @@ def update_sharing_policies(item, parameters = params)
item.policy.set_attributes_with_sharing(policy_params(parameters)) if policy_params(parameters).present?
end
- def update_linked_custom_metadatas(item, parameters = params)
-
- root_key = controller_name.singularize.to_sym
-
- # return no custom metdata is selected
- return unless params[root_key][:custom_metadata_attributes].present?
- return unless params[root_key][:custom_metadata_attributes][:custom_metadata_type_id].present?
- item.custom_metadata.update_linked_custom_metadata(parameters[root_key][:custom_metadata_attributes])
-
- end
-
def initialize_asset
item = class_for_controller_name.new(asset_params)
set_shared_item_variable(item)
diff --git a/lib/seek/config_setting_attributes.yml b/lib/seek/config_setting_attributes.yml
index dd0e0e7fb9..07cc6d9708 100644
--- a/lib/seek/config_setting_attributes.yml
+++ b/lib/seek/config_setting_attributes.yml
@@ -231,13 +231,13 @@ omniauth_github_client_id:
omniauth_github_secret:
encrypt: true
ga4gh_trs_api_enabled:
-custom_metadata_enabled: false
search_results_limit:
convert: :to_i
life_monitor_enabled:
life_monitor_url:
life_monitor_client_id:
life_monitor_client_secret:
+life_monitor_ui_url:
galaxy_instance_name:
galaxy_instance_trs_import_url:
# Controlled vocabs
diff --git a/lib/seek/data/spreadsheet_explorer_representation.rb b/lib/seek/data/spreadsheet_explorer_representation.rb
index bcaac17688..273f286fee 100644
--- a/lib/seek/data/spreadsheet_explorer_representation.rb
+++ b/lib/seek/data/spreadsheet_explorer_representation.rb
@@ -255,6 +255,10 @@ def sheet(x)
@sheets[x]
end
end
+
+ def sheet_names
+ @sheets.map(&:name)
+ end
end
class Style
diff --git a/lib/seek/filterer.rb b/lib/seek/filterer.rb
index a5bcec09e2..b1a6774d1a 100644
--- a/lib/seek/filterer.rb
+++ b/lib/seek/filterer.rb
@@ -3,7 +3,6 @@ class Filterer
# Hard-coded list of available filters for types. Overrides the automatically discovered filters (via `has_filter`).
AVAILABLE_FILTERS = {
Publication: [:query, :programme, :project, :published_year, :publication_type, :author, :organism, :human_disease, :tag],
- Event: [:query, :created_at, :country],
Person: [:query, :programme, :project, :institution, :location, :expertise, :tool]
}.freeze
diff --git a/lib/seek/isa_graph_generator.rb b/lib/seek/isa_graph_generator.rb
index 438e454015..6c18879ed7 100644
--- a/lib/seek/isa_graph_generator.rb
+++ b/lib/seek/isa_graph_generator.rb
@@ -158,10 +158,10 @@ def parents(object)
end
def resolve_association(object, association)
- if object.respond_to?('related_' + association.to_s)
- associations = object.send('related_' + association.to_s)
- elsif object.respond_to?(association)
+ if object.respond_to?(association)
associations = object.send(association)
+ elsif object.respond_to?('related_' + association.to_s)
+ associations = object.send('related_' + association.to_s)
else
return []
end
@@ -189,8 +189,8 @@ def associations(object)
when Study
{
children: [:positioned_assays],
- parents: [:investigation],
- related: [:publications]
+ related: [:publications, :sops],
+ parents: [:investigation]
}
when Assay
{
diff --git a/lib/seek/isa_templates/template_extractor.rb b/lib/seek/isa_templates/template_extractor.rb
index b0487a7e24..236b8d5606 100644
--- a/lib/seek/isa_templates/template_extractor.rb
+++ b/lib/seek/isa_templates/template_extractor.rb
@@ -12,7 +12,7 @@ def self.extract_templates
disable_authorization_checks do
client = Ebi::OlsClient.new
project = Project.find_or_create_by(title: 'Default Project')
- directory = Rails.root.join('config', 'default_data', 'source_types')
+ directory = Seek::Config.append_filestore_path('source_types')
directory_files = Dir.exist?(directory) ? Dir.glob("#{directory}/*.json") : []
raise 'Make sure to upload files that have the ".json" extension. ' if directory_files == []
@@ -172,11 +172,11 @@ def self.seed_isa_tags
end
def self.lockfile
- Rails.root.join('tmp', 'populate_templates.lock')
+ Rails.root.join(Seek::Config.temporary_filestore_path, 'populate_templates.lock')
end
def self.resultfile
- Rails.root.join('tmp', 'populate_templates.result')
+ Rails.root.join(Seek::Config.temporary_filestore_path, 'populate_templates.result')
end
end
end
diff --git a/lib/seek/json_metadata/attribute.rb b/lib/seek/json_metadata/attribute.rb
index d6b4453a78..7049d675a7 100644
--- a/lib/seek/json_metadata/attribute.rb
+++ b/lib/seek/json_metadata/attribute.rb
@@ -16,7 +16,7 @@ module Attribute
# validates that the attribute type is SeekSample if linked_sample_type is set, and vice-versa
validate :linked_sample_type_and_attribute_type_consistency
- delegate :controlled_vocab?, :seek_cv_list?, :seek_sample?, :seek_sample_multi?, :seek_strain?, :seek_resource?, :linked_custom_metadata?, to: :sample_attribute_type, allow_nil: true
+ delegate :controlled_vocab?, :seek_cv_list?, :seek_sample?, :seek_sample_multi?, :seek_strain?, :seek_resource?, :linked_custom_metadata?,:linked_custom_metadata_multi?, to: :sample_attribute_type, allow_nil: true
end
# checks whether the value is blank against the attribute type and base type
@@ -45,7 +45,10 @@ def resolve(value)
end
def pre_process_value(value)
- sample_attribute_type.pre_process_value(value, controlled_vocab: sample_controlled_vocab, linked_sample_type: linked_sample_type)
+ sample_attribute_type.pre_process_value(value,
+ controlled_vocab: sample_controlled_vocab,
+ linked_custom_metadata_type: linked_custom_metadata_type,
+ linked_sample_type: linked_sample_type)
end
private
diff --git a/lib/seek/json_metadata/serialization.rb b/lib/seek/json_metadata/serialization.rb
index 1ed4f4ca03..b6d931faa3 100644
--- a/lib/seek/json_metadata/serialization.rb
+++ b/lib/seek/json_metadata/serialization.rb
@@ -18,13 +18,8 @@ def data
end
def get_attribute_value(attr)
- if attr.try(:sample_attribute_type).try(:linked_custom_metadata?)
- value = self.linked_custom_metadatas.select{|cm| cm.custom_metadata_type_id == attr.linked_custom_metadata_type_id}.select{|cm|cm.custom_metadata_attribute == attr}.first
- else
- attr = attr.accessor_name if attr.is_a?(attribute_class)
- value = data[attr.to_s]
- end
- value
+ attr = attr.accessor_name if attr.is_a?(attribute_class)
+ data[attr.to_s]
end
def set_attribute_value(attr, value)
diff --git a/lib/seek/license.rb b/lib/seek/license.rb
index c1fd083798..4a7c6464f6 100644
--- a/lib/seek/license.rb
+++ b/lib/seek/license.rb
@@ -2,55 +2,84 @@ module Seek
class License < OpenStruct
NULL_LICENSE = 'notspecified'.freeze
- # overrides values taken from the JSON.
- # Preferable to modifying the JSON file directly which is a definitive source and may be replaced with an updated copy
- private_class_method def self.override_json(json)
- json['notspecified']['title'] = I18n.t('null_license')
- json['notspecified']['url'] = Seek::Help::HelpDictionary.instance.help_link(:null_license)
- json
- end
-
- private_class_method def self.organize_licenses(licenses)
- category = {}
+ private_class_method def self.parse_od(licenses)
+ # overrides values taken from the JSON.
+ # Preferable to modifying the JSON file directly which is a definitive source and may be replaced with an updated copy
+ licenses[NULL_LICENSE]['title'] = I18n.t('null_license')
+ licenses[NULL_LICENSE]['url'] = Seek::Help::HelpDictionary.instance.help_link(:null_license)
+ licenses.each_value do |license|
+ license['urls'] = [license['url']].compact_blank
+ end
+ licenses
+ end
- category[:all] = licenses
- .sort_by { |l| l['title'] }
- .sort_by { |l| l.key?('is_generic') && l['is_generic'] ? 0 : 1 }
+ private_class_method def self.parse_spdx(licenses)
+ hash = {}
+ licenses['licenses'].each do |l|
+ hash[l['licenseId']] = {
+ 'title' => l['name'],
+ 'id' => l['licenseId'],
+ 'url' => l['reference'].chomp('.html'),
+ 'urls' => [l['reference'].chomp('.html'), l['reference'], l['detailsUrl'], *l['seeAlso']].compact_blank
+ }
+ end
+ hash
+ end
- category[:data] = category[:all].select do |l|
- l['domain_data'] ||
- l['domain_content'] ||
- l['id'] == NULL_LICENSE
- end
-
- category[:software] = category[:all].select do |l|
- (l['domain_software'] || l['id'] == NULL_LICENSE)
- end
+ private_class_method def self.parse_zenodo(licenses)
+ hash = {}
+ licenses.each do |l|
+ hash[l['id']] = l
+ end
+ hash
+ end
- category
- end
-
- def self.find(id, source = nil)
+ def self.find(id, source = Seek::License.combined)
if (license = find_as_hash(id, source))
new(license)
end
end
- def self.find_as_hash(id, source = nil)
- source ||= Seek::License.open_definition[:all]
- source.find { |l| l['id'] == id }
+ def self.uri_to_id(uri)
+ uri_map[uri]
+ end
+
+ def self.find_as_hash(id, source = Seek::License.combined)
+ source[id]
end
def is_null_license?
id == NULL_LICENSE
end
+ def self.combined
+ @combined ||= open_definition.merge(spdx) do |key, od_license, spdx_license|
+ spdx_license['urls'] |= od_license['urls'] # Merge together alternate URLs
+ spdx_license
+ end
+ end
+
+ def self.spdx
+ @spdx_licenses ||= parse_spdx(JSON.parse(File.read(File.join(Rails.root, 'public', 'spdx_licenses.json'))))
+ end
+
def self.open_definition
- @od_licenses ||= organize_licenses(override_json(JSON.parse(File.read(File.join(Rails.root, 'public', 'od_licenses.json')))).values)
+ @od_licenses ||= parse_od(JSON.parse(File.read(File.join(Rails.root, 'public', 'od_licenses.json'))))
end
def self.zenodo
- @zenodo_licenses ||= organize_licenses(JSON.parse(File.read(File.join(Rails.root, 'public', 'zenodo_licenses.json'))))
+ @zenodo_licenses ||= parse_zenodo(JSON.parse(File.read(File.join(Rails.root, 'public', 'zenodo_licenses.json'))))
+ end
+
+ def self.uri_map
+ return @uri_map if @uri_map
+ @uri_map = {}
+ combined.each do |id, license|
+ (license['urls'] || []).each do |url|
+ @uri_map[url] ||= id
+ end
+ end
+ @uri_map
end
end
end
diff --git a/lib/seek/publishing/publishing_common.rb b/lib/seek/publishing/publishing_common.rb
index f8410d2515..1ce8e6ab71 100644
--- a/lib/seek/publishing/publishing_common.rb
+++ b/lib/seek/publishing/publishing_common.rb
@@ -3,7 +3,7 @@ module Publishing
module PublishingCommon
def self.included(base)
base.before_action :set_asset, only: [:check_related_items, :publish_related_items, :check_gatekeeper_required, :publish, :published]
- base.before_action :set_assets, only: [:batch_publishing_preview]
+ base.before_action :set_assets, :set_investigations, only: [:batch_publishing_preview, :batch_sharing_permission_preview, :batch_sharing_permission_changed]
base.before_action :set_items_for_publishing, only: [:check_gatekeeper_required, :publish]
base.before_action :set_items_for_potential_publishing, only: [:check_related_items, :publish_related_items]
base.before_action :publish_auth, only: [:batch_publishing_preview, :check_related_items, :publish_related_items, :check_gatekeeper_required, :publish, :waiting_approval_assets, :cancel_publishing_request]
@@ -37,12 +37,8 @@ def publish_related_items
def check_gatekeeper_required
@waiting_for_publish_items = @items_for_publishing.select { |item| item.gatekeeper_required? && !User.current_user.person.is_asset_gatekeeper_of?(item) }
@items_for_immediate_publishing = @items_for_publishing - @waiting_for_publish_items
- unless @waiting_for_publish_items.empty?
- respond_to do |format|
- format.html { render template: 'assets/publishing/waiting_approval_list' }
- end
- else
- publish_final_confirmation
+ respond_to do |format|
+ format.html { render template: 'assets/publishing/publish_final_confirmation' }
end
end
@@ -53,12 +49,6 @@ def update_sharing_policies(*args)
super
end
- def publish_final_confirmation
- respond_to do |format|
- format.html { render template: 'assets/publishing/publish_final_confirmation' }
- end
- end
-
def publish
publish_requested_items
@@ -133,21 +123,41 @@ def set_asset
end
def set_assets
- # get the assets that current_user can manage, then take the one that can_publish?
+ # get the assets that current_user can manage
@assets = {}
- publishable_types = Seek::Util.authorized_types.select { |authorized_type| authorized_type.first.try(:is_in_isa_publishable?) }
- publishable_types.each do |klass|
+ Seek::Util.authorized_types.each do |klass|
can_manage_assets = klass.authorized_for 'manage', current_user
- can_manage_assets = can_manage_assets.select(&:can_publish?)
unless can_manage_assets.empty?
@assets[klass.name] = can_manage_assets
end
end
end
+ def set_investigations
+ @investigations = []
+ @assets['Investigation']&.each do |inv|
+ @investigations.push(inv)
+ end
+ @assets_not_in_isa = []
+ @assets.each do |type, klass|
+ next if %w[Investigation Study Assay].include? type
+ klass.each do |asset|
+ if !asset.respond_to?(:investigations) || asset.investigations.empty?
+ @assets_not_in_isa.push(asset)
+ else
+ asset.investigations.each do |inv|
+ next if @investigations.include?(inv)
+ @investigations.push(inv)
+ end
+ end
+ end
+ end
+ end
+
# sets the @items_for_publishing based on the :publish param, and filtered by whether than can_publish?
def set_items_for_publishing
@items_for_publishing = resolve_publish_params(params[:publish]).select(&:can_publish?)
+ @items_cannot_publish = resolve_publish_params(params[:publish]) - @items_for_publishing
end
# sets the @items_for_publishing based on the :publish param, and filtered by whether than can_publish? OR contains_publishable_items?
diff --git a/lib/seek/research_objects/acts_as_snapshottable.rb b/lib/seek/research_objects/acts_as_snapshottable.rb
index 9aef767f1e..30fc276266 100644
--- a/lib/seek/research_objects/acts_as_snapshottable.rb
+++ b/lib/seek/research_objects/acts_as_snapshottable.rb
@@ -28,6 +28,10 @@ def is_snapshottable?
module InstanceMethods
def create_snapshot
+ if self.creators.empty?
+ errors.add(:base, "At least one creator is required. To add, go to Actions -> Manage #{self.class.model_name.human}.")
+ return nil
+ end
Rails.logger.debug("Creating snapshot for: #{self.class.name} #{id}")
snapshot = snapshots.create
filename = "#{self.class.name.underscore}-#{id}-#{snapshot.snapshot_number}.ro.zip"
diff --git a/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb
index d3da68d69e..0968089b3f 100644
--- a/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb
+++ b/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb
@@ -2,9 +2,25 @@ module Seek
module Samples
module AttributeTypeHandlers
class LinkedCustomMetadataAttributeTypeHandler < BaseAttributeHandler
+ class MissingLinkedCustomMetadataTypeException < AttributeHandlerException; end
def test_value(value)
- fail 'Not a custom metadata' unless value.is_a?(CustomMetadata)
+ fail 'Not a custom metadata' unless value.is_a?(Hash)
+ end
+
+ def convert(value)
+ data = Seek::JSONMetadata::Data.new(linked_custom_metadata_type)
+ data.mass_assign(value)
+ data
+ end
+
+ private
+
+ def linked_custom_metadata_type
+ linked_custom_metadata_type = additional_options[:linked_custom_metadata_type]
+ raise MissingLinkedCustomMetadataTypeException unless linked_custom_metadata_type
+
+ linked_custom_metadata_type
end
end
end
diff --git a/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_multi_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_multi_attribute_type_handler.rb
new file mode 100644
index 0000000000..c8cfb0e234
--- /dev/null
+++ b/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_multi_attribute_type_handler.rb
@@ -0,0 +1,19 @@
+module Seek
+ module Samples
+ module AttributeTypeHandlers
+ class LinkedCustomMetadataMultiAttributeTypeHandler < LinkedCustomMetadataAttributeTypeHandler
+
+ def test_value(value)
+ fail 'Not a custom metadata multi' unless value.is_a?(Array)
+ end
+
+ # Params from form are passed as a hash from controller, e.g. { "1" => { "attribute" => "value" } , "2" => ... }
+ def convert(value)
+ value = value.values if value.is_a?(Hash)
+ value.map { |v| super(v) }
+ end
+
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/seek/samples/attribute_type_handlers/seek_sample_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/seek_sample_attribute_type_handler.rb
index ff23bdf209..2284bd5aa8 100644
--- a/lib/seek/samples/attribute_type_handlers/seek_sample_attribute_type_handler.rb
+++ b/lib/seek/samples/attribute_type_handlers/seek_sample_attribute_type_handler.rb
@@ -16,6 +16,10 @@ def test_value(value)
end
end
+ def convert(value)
+ super(value.is_a?(Array) ? value.compact_blank.first : value)
+ end
+
private
def find_resource(value)
diff --git a/lib/seek/samples/base_type.rb b/lib/seek/samples/base_type.rb
index 1091eafdc5..f75ba37ebc 100644
--- a/lib/seek/samples/base_type.rb
+++ b/lib/seek/samples/base_type.rb
@@ -3,7 +3,7 @@ module Samples
# Defines the base type used for sample attributes, and makes them available as constants
# for example Seek::Samples::BaseType.DATE_TIME = 'DateTime'
module BaseType
- ALL_TYPES = %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList LinkedCustomMetadata)
+ ALL_TYPES = %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList LinkedCustomMetadata LinkedCustomMetadataMulti)
ALL_TYPES.each do |type|
BaseType.const_set(type.underscore.upcase, type)
diff --git a/lib/seek/samples/sample_type_editing_constraints.rb b/lib/seek/samples/sample_type_editing_constraints.rb
index 86babde24f..668d047ccc 100644
--- a/lib/seek/samples/sample_type_editing_constraints.rb
+++ b/lib/seek/samples/sample_type_editing_constraints.rb
@@ -82,11 +82,11 @@ def refresh_cache
private
def blanks?(attr)
- analysis_hash[attr.to_sym][:has_blanks]
+ !analysis_hash.key?(attr.to_sym) || analysis_hash[attr.to_sym][:has_blanks]
end
def all_blank?(attr)
- analysis_hash[attr.to_sym][:all_blank]
+ !analysis_hash.key?(attr.to_sym) || analysis_hash[attr.to_sym][:all_blank]
end
def analysis_hash
diff --git a/lib/seek/sharing/sharing_common.rb b/lib/seek/sharing/sharing_common.rb
index 8cfcce6438..f18426e7f0 100644
--- a/lib/seek/sharing/sharing_common.rb
+++ b/lib/seek/sharing/sharing_common.rb
@@ -7,11 +7,11 @@ def self.included(base)
end
def batch_change_permission_for_selected_items
- @items_for_sharing = resolve_sharing_params(params)
+ @items_for_sharing = resolve_sharing_params(params[:publish])
if @items_for_sharing.empty?
flash[:error] = "Please choose at least one item!"
if params[:single_page]
- redirect_to batch_sharing_permission_preview_person_url(current_user.person, { single_page: true })
+ render 'single_pages/sample_batch_sharing_permissions_changed', { layout: false }
else
redirect_to batch_sharing_permission_preview_person_url(current_user.person)
end
@@ -30,51 +30,34 @@ def batch_sharing_permission_preview
@batch_sharing_permission_changed = false
flash[:notice] = nil
respond_to do |format|
- if params[:single_page]
- format.html { render 'single_pages/sample_batch_sharing_permission_preview', { layout: false } }
- else
- format.html { render 'assets/sharing/batch_sharing_permission_preview' }
- end
+ format.html { render 'assets/sharing/batch_sharing_permission_preview' }
end
end
def batch_sharing_permission_changed
-
- @items_for_sharing = resolve_sharing_params(params)
+ @items_for_sharing = resolve_sharing_params(params[:publish])
@batch_sharing_permission_changed = true
- notice_count = 0
- gatekeeper_count = 0
- error_count = 0
- flash[:notice] = "The sharing policies for your selected #{"item".pluralize(@items_for_sharing.size)} were successfully updated: "
- gatekeeper_flash = "Publishing the following #{"item".pluralize(@items_for_sharing.size)} requires approval from a gatekeeper: "
- flash[:error] = "The sharing policies for your selected #{"item".pluralize(@items_for_sharing.size)} were not successfully updated: "
+ @success = []
+ @gatekeeper_required = []
+ @error = []
@items_for_sharing.each do |item|
item.policy.update_with_bulk_sharing_policy(policy_params) if policy_params.present?
- begin
- item.save!
+ if item.save
request_publish_approval_batch_sharing(item) # Has to go before log_publishing_batch_sharing(item)
log_publishing_batch_sharing(item)
if item.is_waiting_approval? && is_gatekeeper_approval_required?(item)
- gatekeeper_count += 1
- gatekeeper_flash += "#{item.title} "
+ @gatekeeper_required << item
else
- notice_count += 1
- flash[:notice] += "#{item.title} "
+ @success << item
end
- rescue Exception => e
- error_count += 1
- flash[:error] += "#{item.title} "
- flash[:error] += "The reason: #{e.message} "
+ else
+ @error << item
end
end
- flash[:notice] = notice_count == 0 ? "": (flash[:notice]+" ").html_safe
- flash[:notice] += gatekeeper_count == 0 ? "": (gatekeeper_flash+" "+"The #{"item".pluralize(gatekeeper_count)} will not be published until approved.").html_safe
- flash.now[:notice] = (notice_count+gatekeeper_count) == 0 ? nil: flash[:notice].html_safe
- flash.now[:error] = error_count == 0 ? nil: (flash[:error]+" ").html_safe
- respond_to do |format|
- if params[:single_page]
- format.html { render 'single_pages/sample_batch_sharing_permission_preview', { layout: false } }
- else
+ if params[:single_page]
+ render 'single_pages/sample_batch_sharing_permissions_changed', { layout: false }
+ else
+ respond_to do |format|
format.html { render 'assets/sharing/batch_sharing_permission_preview' }
end
end
@@ -104,15 +87,12 @@ def request_publish_approval_batch_sharing(object)
# returns an enumeration of assets for bulk sharing change based upon the parameters passed
def resolve_sharing_params(params)
- param_not_isa = params[:share_not_isa] || {}
- param_isa = params[:share_isa] || {}
-
- if param_not_isa.blank? && param_isa.blank?
+ if params.blank?
[@asset].compact
else
assets = []
Seek::Util.authorized_types.each do |klass|
- ids = (param_not_isa[klass.name]&.keys || []) | (param_isa[klass.name]&.keys || [])
+ ids = params[klass.name]&.keys || []
assets += klass.where(id: ids).to_a if ids.any?
end
assets.compact.uniq
diff --git a/lib/seek/stats/activity_counts.rb b/lib/seek/stats/activity_counts.rb
index 2178eab216..66a446a146 100644
--- a/lib/seek/stats/activity_counts.rb
+++ b/lib/seek/stats/activity_counts.rb
@@ -8,6 +8,10 @@ module ActivityCounts
has_many :activity_logs, as: :activity_loggable
end
+ def edit_count
+ count_actions('update')
+ end
+
def download_count
count_actions('download')
end
diff --git a/lib/tasks/seek_upgrades.rake b/lib/tasks/seek_upgrades.rake
index ca6b6e607a..c5ba4e07a7 100644
--- a/lib/tasks/seek_upgrades.rake
+++ b/lib/tasks/seek_upgrades.rake
@@ -8,28 +8,7 @@ namespace :seek do
# these are the tasks required for this version upgrade
task upgrade_version_tasks: %i[
environment
- db:seed:007_sample_attribute_types
- update_missing_openbis_istest
- update_missing_publication_versions
- update_edam_controlled_vocab_keys
- db:seed:011_topics_controlled_vocab
- db:seed:012_operations_controlled_vocab
- db:seed:013_formats_controlled_vocab
- db:seed:014_data_controlled_vocab
- db:seed:015_isa_tags
- db:seed:003_model_formats
- db:seed:004_model_recommended_environments
- remove_orphaned_versions
- refresh_workflow_internals
- remove_scale_annotations
- remove_spreadsheet_annotations
- remove_node_annotations
- convert_roles
- update_edam_annotation_attributes
- remove_orphaned_project_subscriptions
- remove_node_activity_logs
- remove_node_asset_creators
- set_default_sample_type_creators
+ decouple_extracted_samples_policies
]
# these are the tasks that are executes for each upgrade as standard, and rarely change
@@ -66,199 +45,20 @@ namespace :seek do
end
end
- task(update_missing_openbis_istest: :environment) do
- puts '... creating missing is_test for OpenbisEndpoint...'
- create = 0
+ task(decouple_extracted_samples_policies: [:environment]) do
+ puts '... creating independent policies for extracted samples...'
+ decoupled = 0
disable_authorization_checks do
- OpenbisEndpoint.find_each do |openbis_endpoint|
- # check if the publication has a version
- # then create one if missing
- if openbis_endpoint.is_test.nil?
- openbis_endpoint.is_test = false # default -> prod, https
- openbis_endpoint.save
- unless openbis_endpoint.is_test.nil?
- create += 1
- end
+ Sample.find_each do |sample|
+ # check if the sample was extracted from a datafile and their policies are linked
+ if sample.extracted? && sample.policy == sample.originating_data_file&.policy
+ sample.policy = sample.policy.deep_copy
+ sample.policy.save
+ decoupled += 1
end
- # publication.save
end
end
- puts " ... finished creating missing is_test for #{create.to_s} OpenbisEndpoint(s)"
- end
-
- task(update_missing_publication_versions: :environment) do
- puts '... creating missing publications versions ...'
- create = 0
- disable_authorization_checks do
- Publication.find_each do |publication|
- # check if the publication has a version
- # then create one if missing
- if publication.latest_version.nil?
- publication.save_as_new_version 'Version for legacy entries'
- unless publication.latest_version.nil?
- create += 1
- end
- end
- # publication.save
- end
- end
- puts " ... finished creating missing publications versions for #{create.to_s} publications"
- end
-
- task(remove_orphaned_versions: [:environment]) do
- puts 'Removing orphaned versions ...'
- count = 0
- types = [DataFile::Version, Document::Version, Sop::Version, Model::Version, Presentation::Version,
- Sop::Version, Workflow::Version]
- disable_authorization_checks do
- types.each do |type|
- found = type.where.missing(:parent)
- count += found.length
- found.each(&:destroy)
- end
- end
- puts "... finished removing #{count} orphaned versions"
- end
-
- task(remove_scale_annotations: [:environment]) do
- a = Annotation.joins(:annotation_attribute).where(annotation_attribute: { name: ['additional_scale_info', 'scale'] })
- count = a.count
- a.destroy_all
- AnnotationAttribute.where(name:['scale','additional_scale_info']).destroy_all
- puts "Removed #{count} scale related annotations" if count > 0
- end
-
- task(remove_spreadsheet_annotations: [:environment]) do
- annotations = Annotation.where(annotatable_type: 'CellRange')
- count = annotations.count
- values = TextValue.joins(:annotations).where(annotations: { annotatable_type: 'CellRange' })
- values.select{|v| v.annotations.count == 1}.each(&:destroy)
- annotations.destroy_all
- AnnotationAttribute.where(name:'annotation').destroy_all
- puts "Removed #{count} spreadsheet related annotations" if count > 0
- end
-
- task(remove_node_annotations: [:environment]) do
- annotations = Annotation.where(annotatable_type: 'Node')
- count = annotations.count
- values = TextValue.joins(:annotations).where(annotations: { annotatable_type: 'Node' })
- values.select{|v| v.annotations.count == 1}.each(&:destroy)
- annotations.destroy_all
- puts "Removed #{count} Node related annotations" if count > 0
- end
-
- task(convert_roles: [:environment]) do
- puts 'Converting roles...'
- disable_authorization_checks do
- Person.find_each do |person|
- RoleType.for_system.each do |rt|
- mask = rt.id
- if (person.roles_mask & mask) != 0
- Role.where(role_type_id: rt.id, person_id: person.id, scope: nil).first_or_create!
- end
- end
- end
-
- class AdminDefinedRoleProject < ActiveRecord::Base; end
-
- AdminDefinedRoleProject.find_each do |role|
- RoleType.for_projects.each do |rt|
- mask = rt.id
- if (role.role_mask & mask) != 0
- Role.where(role_type_id: rt.id, person_id: role.person_id,
- scope_type: 'Project', scope_id: role.project_id).first_or_create!
- end
- end
- end
-
- class AdminDefinedRoleProgramme < ActiveRecord::Base; end
-
- AdminDefinedRoleProgramme.find_each do |role|
- RoleType.for_programmes.each do |rt|
- mask = rt.id
- if (role.role_mask & mask) != 0
- Role.where(role_type_id: rt.id, person_id: role.person_id,
- scope_type: 'Programme', scope_id: role.programme_id).first_or_create!
- end
- end
- end
- end
- end
-
- task(update_edam_annotation_attributes: [:environment]) do
- defs = {
- "edam_formats": "data_format_annotations",
- "edam_topics": "topic_annotations",
- "edam_operations": "operation_annotations",
- "edam_data": "data_type_annotations"
- }
- defs.each do |old_name,new_name|
- query = AnnotationAttribute.where(name: old_name)
- if query.any?
- puts "Updating EDAM based #{old_name} Annotation Attributes"
- query.update_all(name: new_name)
- end
- end
- end
-
- task(update_edam_controlled_vocab_keys: [:environment]) do
- defs = {
- topics: 'edam_topics',
- operations: 'edam_operations',
- data_formats: 'edam_formats',
- data_types: 'edam_data'
- }
-
- defs.each do |property, old_key|
- new_key = SampleControlledVocab::SystemVocabs.database_key_for_property(property)
- query = SampleControlledVocab.where(key: old_key)
- if query.any?
- puts "Updating key for #{old_key} controlled vocabulary"
- query.update_all(key: new_key)
- end
- end
- end
-
- task(remove_orphaned_project_subscriptions: [:environment]) do
- disable_authorization_checks do
- ProjectSubscription.where.missing(:project).destroy_all
- end
- end
-
- task(remove_node_activity_logs: [:environment]) do
- logs = ActivityLog.where(activity_loggable_type: 'Node')
- puts "Removing #{logs.count} Node related activity logs" if logs.count > 0
- logs.delete_all
- end
-
- task(remove_node_asset_creators: [:environment]) do
- creators = AssetsCreator.where(asset_type: 'Node')
- puts "Removing #{creators.count} Node related asset creators" if creators.count > 0
- creators.delete_all
- end
-
- task(refresh_workflow_internals: [:environment]) do |task|
- ran = only_once(task) do
- Rake::Task['seek:rebuild_workflow_internals'].invoke
- end
-
- puts "Skipping workflow internals rebuild, already done" unless ran
- end
-
- task(set_default_sample_type_creators: [:environment]) do
- ran = only_once('set_default_sample_type_creators') do
- puts "Setting default Sample Type creators"
- count = 0
- SampleType.all.each do |sample_type|
- if sample_type.assets_creators.empty?
- sample_type.assets_creators.build(creator: sample_type.contributor).save!
- count += 1
- end
- end
- puts "#{count} Sample Types updated"
- end
-
- puts "Skipping setting default Sample Type creators, as already set" unless ran
+ puts " ... finished creating independent policies of #{decoupled.to_s} extracted samples"
end
private
diff --git a/public/spdx_licenses.json b/public/spdx_licenses.json
new file mode 100644
index 0000000000..9b21d11b73
--- /dev/null
+++ b/public/spdx_licenses.json
@@ -0,0 +1,7011 @@
+{
+ "licenseListVersion": "3.21",
+ "licenses": [
+ {
+ "reference": "https://spdx.org/licenses/LPL-1.02.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LPL-1.02.json",
+ "referenceNumber": 0,
+ "name": "Lucent Public License v1.02",
+ "licenseId": "LPL-1.02",
+ "seeAlso": [
+ "http://plan9.bell-labs.com/plan9/license.html",
+ "https://opensource.org/licenses/LPL-1.02"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0.json",
+ "referenceNumber": 1,
+ "name": "GNU General Public License v2.0 only",
+ "licenseId": "GPL-2.0",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html",
+ "https://opensource.org/licenses/GPL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NTP.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NTP.json",
+ "referenceNumber": 2,
+ "name": "NTP License",
+ "licenseId": "NTP",
+ "seeAlso": [
+ "https://opensource.org/licenses/NTP"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OFL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OFL-1.1.json",
+ "referenceNumber": 3,
+ "name": "SIL Open Font License 1.1",
+ "licenseId": "OFL-1.1",
+ "seeAlso": [
+ "http://scripts.sil.org/cms/scripts/page.php?item_id\u003dOFL_web",
+ "https://opensource.org/licenses/OFL-1.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Bahyph.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Bahyph.json",
+ "referenceNumber": 4,
+ "name": "Bahyph License",
+ "licenseId": "Bahyph",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Bahyph"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Hippocratic-2.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Hippocratic-2.1.json",
+ "referenceNumber": 5,
+ "name": "Hippocratic License 2.1",
+ "licenseId": "Hippocratic-2.1",
+ "seeAlso": [
+ "https://firstdonoharm.dev/version/2/1/license.html",
+ "https://github.com/EthicalSource/hippocratic-license/blob/58c0e646d64ff6fbee275bfe2b9492f914e3ab2a/LICENSE.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/VOSTROM.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/VOSTROM.json",
+ "referenceNumber": 6,
+ "name": "VOSTROM Public License for Open Source",
+ "licenseId": "VOSTROM",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/VOSTROM"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-3.0-AT.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-3.0-AT.json",
+ "referenceNumber": 7,
+ "name": "Creative Commons Attribution 3.0 Austria",
+ "licenseId": "CC-BY-3.0-AT",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/3.0/at/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-2.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-2.5.json",
+ "referenceNumber": 8,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 2.5 Generic",
+ "licenseId": "CC-BY-NC-SA-2.5",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/2.5/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/W3C-20150513.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/W3C-20150513.json",
+ "referenceNumber": 9,
+ "name": "W3C Software Notice and Document License (2015-05-13)",
+ "licenseId": "W3C-20150513",
+ "seeAlso": [
+ "https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-3.0-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-3.0-only.json",
+ "referenceNumber": 10,
+ "name": "GNU Lesser General Public License v3.0 only",
+ "licenseId": "LGPL-3.0-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/lgpl-3.0-standalone.html",
+ "https://www.gnu.org/licenses/lgpl+gpl-3.0.txt",
+ "https://opensource.org/licenses/LGPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.1-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.1-only.json",
+ "referenceNumber": 11,
+ "name": "GNU Free Documentation License v1.1 only",
+ "licenseId": "GFDL-1.1-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.1.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CDL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CDL-1.0.json",
+ "referenceNumber": 12,
+ "name": "Common Documentation License 1.0",
+ "licenseId": "CDL-1.0",
+ "seeAlso": [
+ "http://www.opensource.apple.com/cdl/",
+ "https://fedoraproject.org/wiki/Licensing/Common_Documentation_License",
+ "https://www.gnu.org/licenses/license-list.html#ACDL"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-ND-2.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-ND-2.5.json",
+ "referenceNumber": 13,
+ "name": "Creative Commons Attribution No Derivatives 2.5 Generic",
+ "licenseId": "CC-BY-ND-2.5",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nd/2.5/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-3.0-IGO.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-3.0-IGO.json",
+ "referenceNumber": 14,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 3.0 IGO",
+ "licenseId": "CC-BY-NC-SA-3.0-IGO",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/3.0/igo/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OGC-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OGC-1.0.json",
+ "referenceNumber": 15,
+ "name": "OGC Software License, Version 1.0",
+ "licenseId": "OGC-1.0",
+ "seeAlso": [
+ "https://www.ogc.org/ogc/software/1.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/RPL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/RPL-1.1.json",
+ "referenceNumber": 16,
+ "name": "Reciprocal Public License 1.1",
+ "licenseId": "RPL-1.1",
+ "seeAlso": [
+ "https://opensource.org/licenses/RPL-1.1"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0-or-later.json",
+ "referenceNumber": 17,
+ "name": "GNU General Public License v2.0 or later",
+ "licenseId": "GPL-2.0-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html",
+ "https://opensource.org/licenses/GPL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Sendmail.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Sendmail.json",
+ "referenceNumber": 18,
+ "name": "Sendmail License",
+ "licenseId": "Sendmail",
+ "seeAlso": [
+ "http://www.sendmail.com/pdfs/open_source/sendmail_license.pdf",
+ "https://web.archive.org/web/20160322142305/https://www.sendmail.com/pdfs/open_source/sendmail_license.pdf"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-2.0-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-2.0-only.json",
+ "referenceNumber": 19,
+ "name": "GNU Library General Public License v2 only",
+ "licenseId": "LGPL-2.0-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/lgpl-2.0-standalone.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OSL-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OSL-3.0.json",
+ "referenceNumber": 20,
+ "name": "Open Software License 3.0",
+ "licenseId": "OSL-3.0",
+ "seeAlso": [
+ "https://web.archive.org/web/20120101081418/http://rosenlaw.com:80/OSL3.0.htm",
+ "https://opensource.org/licenses/OSL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Libpng.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Libpng.json",
+ "referenceNumber": 21,
+ "name": "libpng License",
+ "licenseId": "Libpng",
+ "seeAlso": [
+ "http://www.libpng.org/pub/png/src/libpng-LICENSE.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-2-Clause-FreeBSD.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/BSD-2-Clause-FreeBSD.json",
+ "referenceNumber": 22,
+ "name": "BSD 2-Clause FreeBSD License",
+ "licenseId": "BSD-2-Clause-FreeBSD",
+ "seeAlso": [
+ "http://www.freebsd.org/copyright/freebsd-license.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/MS-RL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MS-RL.json",
+ "referenceNumber": 23,
+ "name": "Microsoft Reciprocal License",
+ "licenseId": "MS-RL",
+ "seeAlso": [
+ "http://www.microsoft.com/opensource/licenses.mspx",
+ "https://opensource.org/licenses/MS-RL"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-CMU.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-CMU.json",
+ "referenceNumber": 24,
+ "name": "CMU License",
+ "licenseId": "MIT-CMU",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing:MIT?rd\u003dLicensing/MIT#CMU_Style",
+ "https://github.com/python-pillow/Pillow/blob/fffb426092c8db24a5f4b6df243a8a3c01fb63cd/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Linux-OpenIB.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Linux-OpenIB.json",
+ "referenceNumber": 25,
+ "name": "Linux Kernel Variant of OpenIB.org license",
+ "licenseId": "Linux-OpenIB",
+ "seeAlso": [
+ "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/infiniband/core/sa.h"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Latex2e-translated-notice.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Latex2e-translated-notice.json",
+ "referenceNumber": 26,
+ "name": "Latex2e with translated notice permission",
+ "licenseId": "Latex2e-translated-notice",
+ "seeAlso": [
+ "https://git.savannah.gnu.org/cgit/indent.git/tree/doc/indent.texi?id\u003da74c6b4ee49397cf330b333da1042bffa60ed14f#n74"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/psutils.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/psutils.json",
+ "referenceNumber": 27,
+ "name": "psutils License",
+ "licenseId": "psutils",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/psutils"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Clips.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Clips.json",
+ "referenceNumber": 28,
+ "name": "Clips License",
+ "licenseId": "Clips",
+ "seeAlso": [
+ "https://github.com/DrItanium/maya/blob/master/LICENSE.CLIPS"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-2.0-FR.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-2.0-FR.json",
+ "referenceNumber": 29,
+ "name": "Creative Commons Attribution-NonCommercial-ShareAlike 2.0 France",
+ "licenseId": "CC-BY-NC-SA-2.0-FR",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/2.0/fr/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/EUDatagrid.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EUDatagrid.json",
+ "referenceNumber": 30,
+ "name": "EU DataGrid Software License",
+ "licenseId": "EUDatagrid",
+ "seeAlso": [
+ "http://eu-datagrid.web.cern.ch/eu-datagrid/license.html",
+ "https://opensource.org/licenses/EUDatagrid"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-ND-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-ND-3.0.json",
+ "referenceNumber": 31,
+ "name": "Creative Commons Attribution No Derivatives 3.0 Unported",
+ "licenseId": "CC-BY-ND-3.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nd/3.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/w3m.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/w3m.json",
+ "referenceNumber": 32,
+ "name": "w3m License",
+ "licenseId": "w3m",
+ "seeAlso": [
+ "https://github.com/tats/w3m/blob/master/COPYING"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.3.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.3.json",
+ "referenceNumber": 33,
+ "name": "Open LDAP Public License v2.3",
+ "licenseId": "OLDAP-2.3",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003dd32cf54a32d581ab475d23c810b0a7fbaf8d63c3"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/AGPL-3.0-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AGPL-3.0-only.json",
+ "referenceNumber": 34,
+ "name": "GNU Affero General Public License v3.0 only",
+ "licenseId": "AGPL-3.0-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/agpl.txt",
+ "https://opensource.org/licenses/AGPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/AGPL-1.0-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AGPL-1.0-or-later.json",
+ "referenceNumber": 35,
+ "name": "Affero General Public License v1.0 or later",
+ "licenseId": "AGPL-1.0-or-later",
+ "seeAlso": [
+ "http://www.affero.org/oagpl.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/TMate.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TMate.json",
+ "referenceNumber": 36,
+ "name": "TMate Open Source License",
+ "licenseId": "TMate",
+ "seeAlso": [
+ "http://svnkit.com/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.3-invariants-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.3-invariants-only.json",
+ "referenceNumber": 37,
+ "name": "GNU Free Documentation License v1.3 only - invariants",
+ "licenseId": "GFDL-1.3-invariants-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/fdl-1.3.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SchemeReport.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SchemeReport.json",
+ "referenceNumber": 38,
+ "name": "Scheme Language Report License",
+ "licenseId": "SchemeReport",
+ "seeAlso": [],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NAIST-2003.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NAIST-2003.json",
+ "referenceNumber": 39,
+ "name": "Nara Institute of Science and Technology License (2003)",
+ "licenseId": "NAIST-2003",
+ "seeAlso": [
+ "https://enterprise.dejacode.com/licenses/public/naist-2003/#license-text",
+ "https://github.com/nodejs/node/blob/4a19cc8947b1bba2b2d27816ec3d0edf9b28e503/LICENSE#L343"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/eCos-2.0.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/eCos-2.0.json",
+ "referenceNumber": 40,
+ "name": "eCos license version 2.0",
+ "licenseId": "eCos-2.0",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/ecos-license.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-4-Clause-Shortened.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-4-Clause-Shortened.json",
+ "referenceNumber": 41,
+ "name": "BSD 4 Clause Shortened",
+ "licenseId": "BSD-4-Clause-Shortened",
+ "seeAlso": [
+ "https://metadata.ftp-master.debian.org/changelogs//main/a/arpwatch/arpwatch_2.1a15-7_copyright"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/PDDL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/PDDL-1.0.json",
+ "referenceNumber": 42,
+ "name": "Open Data Commons Public Domain Dedication \u0026 License 1.0",
+ "licenseId": "PDDL-1.0",
+ "seeAlso": [
+ "http://opendatacommons.org/licenses/pddl/1.0/",
+ "https://opendatacommons.org/licenses/pddl/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/XSkat.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/XSkat.json",
+ "referenceNumber": 43,
+ "name": "XSkat License",
+ "licenseId": "XSkat",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/XSkat_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-ND-4.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-ND-4.0.json",
+ "referenceNumber": 44,
+ "name": "Creative Commons Attribution No Derivatives 4.0 International",
+ "licenseId": "CC-BY-ND-4.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nd/4.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-LBNL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-LBNL.json",
+ "referenceNumber": 45,
+ "name": "Lawrence Berkeley National Labs BSD variant license",
+ "licenseId": "BSD-3-Clause-LBNL",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/LBNLBSD"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-open-group.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-open-group.json",
+ "referenceNumber": 46,
+ "name": "MIT Open Group variant",
+ "licenseId": "MIT-open-group",
+ "seeAlso": [
+ "https://gitlab.freedesktop.org/xorg/app/iceauth/-/blob/master/COPYING",
+ "https://gitlab.freedesktop.org/xorg/app/xvinfo/-/blob/master/COPYING",
+ "https://gitlab.freedesktop.org/xorg/app/xsetroot/-/blob/master/COPYING",
+ "https://gitlab.freedesktop.org/xorg/app/xauth/-/blob/master/COPYING"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/UnixCrypt.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/UnixCrypt.json",
+ "referenceNumber": 47,
+ "name": "UnixCrypt License",
+ "licenseId": "UnixCrypt",
+ "seeAlso": [
+ "https://foss.heptapod.net/python-libs/passlib/-/blob/branch/stable/LICENSE#L70",
+ "https://opensource.apple.com/source/JBoss/JBoss-737/jboss-all/jetty/src/main/org/mortbay/util/UnixCrypt.java.auto.html",
+ "https://archive.eclipse.org/jetty/8.0.1.v20110908/xref/org/eclipse/jetty/http/security/UnixCrypt.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LiLiQ-P-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LiLiQ-P-1.1.json",
+ "referenceNumber": 48,
+ "name": "Licence Libre du Québec – Permissive version 1.1",
+ "licenseId": "LiLiQ-P-1.1",
+ "seeAlso": [
+ "https://forge.gouv.qc.ca/licence/fr/liliq-v1-1/",
+ "http://opensource.org/licenses/LiLiQ-P-1.1"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Eurosym.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Eurosym.json",
+ "referenceNumber": 49,
+ "name": "Eurosym License",
+ "licenseId": "Eurosym",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Eurosym"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/JPNIC.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/JPNIC.json",
+ "referenceNumber": 50,
+ "name": "Japan Network Information Center License",
+ "licenseId": "JPNIC",
+ "seeAlso": [
+ "https://gitlab.isc.org/isc-projects/bind9/blob/master/COPYRIGHT#L366"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NPL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NPL-1.1.json",
+ "referenceNumber": 51,
+ "name": "Netscape Public License v1.1",
+ "licenseId": "NPL-1.1",
+ "seeAlso": [
+ "http://www.mozilla.org/MPL/NPL/1.1/"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NLOD-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NLOD-2.0.json",
+ "referenceNumber": 52,
+ "name": "Norwegian Licence for Open Government Data (NLOD) 2.0",
+ "licenseId": "NLOD-2.0",
+ "seeAlso": [
+ "http://data.norge.no/nlod/en/2.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NPL-1.0.json",
+ "referenceNumber": 53,
+ "name": "Netscape Public License v1.0",
+ "licenseId": "NPL-1.0",
+ "seeAlso": [
+ "http://www.mozilla.org/MPL/NPL/1.0/"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-2.1-JP.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-2.1-JP.json",
+ "referenceNumber": 54,
+ "name": "Creative Commons Attribution Share Alike 2.1 Japan",
+ "licenseId": "CC-BY-SA-2.1-JP",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/2.1/jp/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-3.0.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-3.0.json",
+ "referenceNumber": 55,
+ "name": "GNU General Public License v3.0 only",
+ "licenseId": "GPL-3.0",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/gpl-3.0-standalone.html",
+ "https://opensource.org/licenses/GPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPLLR.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LGPLLR.json",
+ "referenceNumber": 56,
+ "name": "Lesser General Public License For Linguistic Resources",
+ "licenseId": "LGPLLR",
+ "seeAlso": [
+ "http://www-igm.univ-mlv.fr/~unitex/lgpllr.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/wxWindows.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/wxWindows.json",
+ "referenceNumber": 57,
+ "name": "wxWindows Library License",
+ "licenseId": "wxWindows",
+ "seeAlso": [
+ "https://opensource.org/licenses/WXwindows"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/PHP-3.01.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/PHP-3.01.json",
+ "referenceNumber": 58,
+ "name": "PHP License v3.01",
+ "licenseId": "PHP-3.01",
+ "seeAlso": [
+ "http://www.php.net/license/3_01.txt"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.1.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.1.json",
+ "referenceNumber": 59,
+ "name": "GNU Free Documentation License v1.1",
+ "licenseId": "GFDL-1.1",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.1.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Ruby.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Ruby.json",
+ "referenceNumber": 60,
+ "name": "Ruby License",
+ "licenseId": "Ruby",
+ "seeAlso": [
+ "http://www.ruby-lang.org/en/LICENSE.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-2.0.json",
+ "referenceNumber": 61,
+ "name": "Creative Commons Attribution 2.0 Generic",
+ "licenseId": "CC-BY-2.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/2.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/QPL-1.0-INRIA-2004.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/QPL-1.0-INRIA-2004.json",
+ "referenceNumber": 62,
+ "name": "Q Public License 1.0 - INRIA 2004 variant",
+ "licenseId": "QPL-1.0-INRIA-2004",
+ "seeAlso": [
+ "https://github.com/maranget/hevea/blob/master/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Aladdin.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Aladdin.json",
+ "referenceNumber": 63,
+ "name": "Aladdin Free Public License",
+ "licenseId": "Aladdin",
+ "seeAlso": [
+ "http://pages.cs.wisc.edu/~ghost/doc/AFPL/6.01/Public.htm"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ODC-By-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ODC-By-1.0.json",
+ "referenceNumber": 64,
+ "name": "Open Data Commons Attribution License v1.0",
+ "licenseId": "ODC-By-1.0",
+ "seeAlso": [
+ "https://opendatacommons.org/licenses/by/1.0/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Intel-ACPI.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Intel-ACPI.json",
+ "referenceNumber": 65,
+ "name": "Intel ACPI Software License Agreement",
+ "licenseId": "Intel-ACPI",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Intel_ACPI_Software_License_Agreement"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-2.1-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-2.1-or-later.json",
+ "referenceNumber": 66,
+ "name": "GNU Lesser General Public License v2.1 or later",
+ "licenseId": "LGPL-2.1-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html",
+ "https://opensource.org/licenses/LGPL-2.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/MPL-2.0-no-copyleft-exception.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MPL-2.0-no-copyleft-exception.json",
+ "referenceNumber": 67,
+ "name": "Mozilla Public License 2.0 (no copyleft exception)",
+ "licenseId": "MPL-2.0-no-copyleft-exception",
+ "seeAlso": [
+ "https://www.mozilla.org/MPL/2.0/",
+ "https://opensource.org/licenses/MPL-2.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0-with-bison-exception.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0-with-bison-exception.json",
+ "referenceNumber": 68,
+ "name": "GNU General Public License v2.0 w/Bison exception",
+ "licenseId": "GPL-2.0-with-bison-exception",
+ "seeAlso": [
+ "http://git.savannah.gnu.org/cgit/bison.git/tree/data/yacc.c?id\u003d193d7c7054ba7197b0789e14965b739162319b5e#n141"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Parity-6.0.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Parity-6.0.0.json",
+ "referenceNumber": 69,
+ "name": "The Parity Public License 6.0.0",
+ "licenseId": "Parity-6.0.0",
+ "seeAlso": [
+ "https://paritylicense.com/versions/6.0.0.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Zlib.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Zlib.json",
+ "referenceNumber": 70,
+ "name": "zlib License",
+ "licenseId": "Zlib",
+ "seeAlso": [
+ "http://www.zlib.net/zlib_license.html",
+ "https://opensource.org/licenses/Zlib"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-1.0.json",
+ "referenceNumber": 71,
+ "name": "Creative Commons Attribution Share Alike 1.0 Generic",
+ "licenseId": "CC-BY-SA-1.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/1.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-2.0-UK.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-2.0-UK.json",
+ "referenceNumber": 72,
+ "name": "Creative Commons Attribution Share Alike 2.0 England and Wales",
+ "licenseId": "CC-BY-SA-2.0-UK",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/2.0/uk/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ADSL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ADSL.json",
+ "referenceNumber": 73,
+ "name": "Amazon Digital Services License",
+ "licenseId": "ADSL",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/AmazonDigitalServicesLicense"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Net-SNMP.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Net-SNMP.json",
+ "referenceNumber": 74,
+ "name": "Net-SNMP License",
+ "licenseId": "Net-SNMP",
+ "seeAlso": [
+ "http://net-snmp.sourceforge.net/about/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/YPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/YPL-1.0.json",
+ "referenceNumber": 75,
+ "name": "Yahoo! Public License v1.0",
+ "licenseId": "YPL-1.0",
+ "seeAlso": [
+ "http://www.zimbra.com/license/yahoo_public_license_1.0.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Baekmuk.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Baekmuk.json",
+ "referenceNumber": 76,
+ "name": "Baekmuk License",
+ "licenseId": "Baekmuk",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing:Baekmuk?rd\u003dLicensing/Baekmuk"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BitTorrent-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BitTorrent-1.1.json",
+ "referenceNumber": 77,
+ "name": "BitTorrent Open Source License v1.1",
+ "licenseId": "BitTorrent-1.1",
+ "seeAlso": [
+ "http://directory.fsf.org/wiki/License:BitTorrentOSL1.1"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Arphic-1999.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Arphic-1999.json",
+ "referenceNumber": 78,
+ "name": "Arphic Public License",
+ "licenseId": "Arphic-1999",
+ "seeAlso": [
+ "http://ftp.gnu.org/gnu/non-gnu/chinese-fonts-truetype/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-Warranty.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-Warranty.json",
+ "referenceNumber": 79,
+ "name": "BSD 3-Clause No Nuclear Warranty",
+ "licenseId": "BSD-3-Clause-No-Nuclear-Warranty",
+ "seeAlso": [
+ "https://jogamp.org/git/?p\u003dgluegen.git;a\u003dblob_plain;f\u003dLICENSE.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MTLL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MTLL.json",
+ "referenceNumber": 80,
+ "name": "Matrix Template Library License",
+ "licenseId": "MTLL",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Matrix_Template_Library_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/JPL-image.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/JPL-image.json",
+ "referenceNumber": 81,
+ "name": "JPL Image Use Policy",
+ "licenseId": "JPL-image",
+ "seeAlso": [
+ "https://www.jpl.nasa.gov/jpl-image-use-policy"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-2.0+.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-2.0+.json",
+ "referenceNumber": 82,
+ "name": "GNU Library General Public License v2 or later",
+ "licenseId": "LGPL-2.0+",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/lgpl-2.0-standalone.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/ZPL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ZPL-2.0.json",
+ "referenceNumber": 83,
+ "name": "Zope Public License 2.0",
+ "licenseId": "ZPL-2.0",
+ "seeAlso": [
+ "http://old.zope.org/Resources/License/ZPL-2.0",
+ "https://opensource.org/licenses/ZPL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/TCP-wrappers.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TCP-wrappers.json",
+ "referenceNumber": 84,
+ "name": "TCP Wrappers License",
+ "licenseId": "TCP-wrappers",
+ "seeAlso": [
+ "http://rc.quest.com/topics/openssh/license.php#tcpwrappers"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-1.0-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GPL-1.0-or-later.json",
+ "referenceNumber": 85,
+ "name": "GNU General Public License v1.0 or later",
+ "licenseId": "GPL-1.0-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/gpl-1.0-standalone.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/PSF-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/PSF-2.0.json",
+ "referenceNumber": 86,
+ "name": "Python Software Foundation License 2.0",
+ "licenseId": "PSF-2.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/Python-2.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0-with-font-exception.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0-with-font-exception.json",
+ "referenceNumber": 87,
+ "name": "GNU General Public License v2.0 w/Font exception",
+ "licenseId": "GPL-2.0-with-font-exception",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/gpl-faq.html#FontException"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Nokia.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Nokia.json",
+ "referenceNumber": 88,
+ "name": "Nokia Open Source License",
+ "licenseId": "Nokia",
+ "seeAlso": [
+ "https://opensource.org/licenses/nokia"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Entessa.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Entessa.json",
+ "referenceNumber": 89,
+ "name": "Entessa Public License v1.0",
+ "licenseId": "Entessa",
+ "seeAlso": [
+ "https://opensource.org/licenses/Entessa"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/AMPAS.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AMPAS.json",
+ "referenceNumber": 90,
+ "name": "Academy of Motion Picture Arts and Sciences BSD",
+ "licenseId": "AMPAS",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/BSD#AMPASBSD"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/TU-Berlin-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TU-Berlin-1.0.json",
+ "referenceNumber": 91,
+ "name": "Technische Universitaet Berlin License 1.0",
+ "licenseId": "TU-Berlin-1.0",
+ "seeAlso": [
+ "https://github.com/swh/ladspa/blob/7bf6f3799fdba70fda297c2d8fd9f526803d9680/gsm/COPYRIGHT"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Adobe-Glyph.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Adobe-Glyph.json",
+ "referenceNumber": 92,
+ "name": "Adobe Glyph List License",
+ "licenseId": "Adobe-Glyph",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/MIT#AdobeGlyph"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/DL-DE-BY-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/DL-DE-BY-2.0.json",
+ "referenceNumber": 93,
+ "name": "Data licence Germany – attribution – version 2.0",
+ "licenseId": "DL-DE-BY-2.0",
+ "seeAlso": [
+ "https://www.govdata.de/dl-de/by-2-0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MPL-1.0.json",
+ "referenceNumber": 94,
+ "name": "Mozilla Public License 1.0",
+ "licenseId": "MPL-1.0",
+ "seeAlso": [
+ "http://www.mozilla.org/MPL/MPL-1.0.html",
+ "https://opensource.org/licenses/MPL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Dotseqn.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Dotseqn.json",
+ "referenceNumber": 95,
+ "name": "Dotseqn License",
+ "licenseId": "Dotseqn",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Dotseqn"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/IBM-pibs.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/IBM-pibs.json",
+ "referenceNumber": 96,
+ "name": "IBM PowerPC Initialization and Boot Software",
+ "licenseId": "IBM-pibs",
+ "seeAlso": [
+ "http://git.denx.de/?p\u003du-boot.git;a\u003dblob;f\u003darch/powerpc/cpu/ppc4xx/miiphy.c;h\u003d297155fdafa064b955e53e9832de93bfb0cfb85b;hb\u003d9fab4bf4cc077c21e43941866f3f2c196f28670d"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Plexus.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Plexus.json",
+ "referenceNumber": 97,
+ "name": "Plexus Classworlds License",
+ "licenseId": "Plexus",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Plexus_Classworlds_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/HP-1986.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/HP-1986.json",
+ "referenceNumber": 98,
+ "name": "Hewlett-Packard 1986 License",
+ "licenseId": "HP-1986",
+ "seeAlso": [
+ "https://sourceware.org/git/?p\u003dnewlib-cygwin.git;a\u003dblob;f\u003dnewlib/libc/machine/hppa/memchr.S;h\u003d1cca3e5e8867aa4bffef1f75a5c1bba25c0c441e;hb\u003dHEAD#l2"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LPPL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LPPL-1.1.json",
+ "referenceNumber": 99,
+ "name": "LaTeX Project Public License v1.1",
+ "licenseId": "LPPL-1.1",
+ "seeAlso": [
+ "http://www.latex-project.org/lppl/lppl-1-1.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-1.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-1.2.json",
+ "referenceNumber": 100,
+ "name": "Open LDAP Public License v1.2",
+ "licenseId": "OLDAP-1.2",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003d42b0383c50c299977b5893ee695cf4e486fb0dc7"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ZPL-2.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ZPL-2.1.json",
+ "referenceNumber": 101,
+ "name": "Zope Public License 2.1",
+ "licenseId": "ZPL-2.1",
+ "seeAlso": [
+ "http://old.zope.org/Resources/ZPL/"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LPL-1.0.json",
+ "referenceNumber": 102,
+ "name": "Lucent Public License Version 1.0",
+ "licenseId": "LPL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/LPL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/HPND-sell-variant-MIT-disclaimer.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/HPND-sell-variant-MIT-disclaimer.json",
+ "referenceNumber": 103,
+ "name": "HPND sell variant with MIT disclaimer",
+ "licenseId": "HPND-sell-variant-MIT-disclaimer",
+ "seeAlso": [
+ "https://github.com/sigmavirus24/x11-ssh-askpass/blob/master/README"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OFFIS.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OFFIS.json",
+ "referenceNumber": 104,
+ "name": "OFFIS License",
+ "licenseId": "OFFIS",
+ "seeAlso": [
+ "https://sourceforge.net/p/xmedcon/code/ci/master/tree/libs/dicom/README"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CrystalStacker.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CrystalStacker.json",
+ "referenceNumber": 105,
+ "name": "CrystalStacker License",
+ "licenseId": "CrystalStacker",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing:CrystalStacker?rd\u003dLicensing/CrystalStacker"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Adobe-2006.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Adobe-2006.json",
+ "referenceNumber": 106,
+ "name": "Adobe Systems Incorporated Source Code License Agreement",
+ "licenseId": "Adobe-2006",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/AdobeLicense"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Zimbra-1.3.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Zimbra-1.3.json",
+ "referenceNumber": 107,
+ "name": "Zimbra Public License v1.3",
+ "licenseId": "Zimbra-1.3",
+ "seeAlso": [
+ "http://web.archive.org/web/20100302225219/http://www.zimbra.com/license/zimbra-public-license-1-3.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CUA-OPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CUA-OPL-1.0.json",
+ "referenceNumber": 108,
+ "name": "CUA Office Public License v1.0",
+ "licenseId": "CUA-OPL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/CUA-OPL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/EUPL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EUPL-1.1.json",
+ "referenceNumber": 109,
+ "name": "European Union Public License 1.1",
+ "licenseId": "EUPL-1.1",
+ "seeAlso": [
+ "https://joinup.ec.europa.eu/software/page/eupl/licence-eupl",
+ "https://joinup.ec.europa.eu/sites/default/files/custom-page/attachment/eupl1.1.-licence-en_0.pdf",
+ "https://opensource.org/licenses/EUPL-1.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/IJG.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/IJG.json",
+ "referenceNumber": 110,
+ "name": "Independent JPEG Group License",
+ "licenseId": "IJG",
+ "seeAlso": [
+ "http://dev.w3.org/cvsweb/Amaya/libjpeg/Attic/README?rev\u003d1.2"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Afmparse.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Afmparse.json",
+ "referenceNumber": 111,
+ "name": "Afmparse License",
+ "licenseId": "Afmparse",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Afmparse"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/PolyForm-Noncommercial-1.0.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/PolyForm-Noncommercial-1.0.0.json",
+ "referenceNumber": 112,
+ "name": "PolyForm Noncommercial License 1.0.0",
+ "licenseId": "PolyForm-Noncommercial-1.0.0",
+ "seeAlso": [
+ "https://polyformproject.org/licenses/noncommercial/1.0.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NCGL-UK-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NCGL-UK-2.0.json",
+ "referenceNumber": 113,
+ "name": "Non-Commercial Government Licence",
+ "licenseId": "NCGL-UK-2.0",
+ "seeAlso": [
+ "http://www.nationalarchives.gov.uk/doc/non-commercial-government-licence/version/2/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/EPL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EPL-2.0.json",
+ "referenceNumber": 114,
+ "name": "Eclipse Public License 2.0",
+ "licenseId": "EPL-2.0",
+ "seeAlso": [
+ "https://www.eclipse.org/legal/epl-2.0",
+ "https://www.opensource.org/licenses/EPL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-ND-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-ND-1.0.json",
+ "referenceNumber": 115,
+ "name": "Creative Commons Attribution No Derivatives 1.0 Generic",
+ "licenseId": "CC-BY-ND-1.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nd/1.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-ND-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-ND-2.0.json",
+ "referenceNumber": 116,
+ "name": "Creative Commons Attribution No Derivatives 2.0 Generic",
+ "licenseId": "CC-BY-ND-2.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nd/2.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OFL-1.1-no-RFN.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OFL-1.1-no-RFN.json",
+ "referenceNumber": 117,
+ "name": "SIL Open Font License 1.1 with no Reserved Font Name",
+ "licenseId": "OFL-1.1-no-RFN",
+ "seeAlso": [
+ "http://scripts.sil.org/cms/scripts/page.php?item_id\u003dOFL_web",
+ "https://opensource.org/licenses/OFL-1.1"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/HPND-Markus-Kuhn.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/HPND-Markus-Kuhn.json",
+ "referenceNumber": 118,
+ "name": "Historical Permission Notice and Disclaimer - Markus Kuhn variant",
+ "licenseId": "HPND-Markus-Kuhn",
+ "seeAlso": [
+ "https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c",
+ "https://sourceware.org/git/?p\u003dbinutils-gdb.git;a\u003dblob;f\u003dreadline/readline/support/wcwidth.c;h\u003d0f5ec995796f4813abbcf4972aec0378ab74722a;hb\u003dHEAD#l55"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Xnet.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Xnet.json",
+ "referenceNumber": 119,
+ "name": "X.Net License",
+ "licenseId": "Xnet",
+ "seeAlso": [
+ "https://opensource.org/licenses/Xnet"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CNRI-Python.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CNRI-Python.json",
+ "referenceNumber": 120,
+ "name": "CNRI Python License",
+ "licenseId": "CNRI-Python",
+ "seeAlso": [
+ "https://opensource.org/licenses/CNRI-Python"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Zimbra-1.4.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Zimbra-1.4.json",
+ "referenceNumber": 121,
+ "name": "Zimbra Public License v1.4",
+ "licenseId": "Zimbra-1.4",
+ "seeAlso": [
+ "http://www.zimbra.com/legal/zimbra-public-license-1-4"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SGI-B-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SGI-B-1.0.json",
+ "referenceNumber": 122,
+ "name": "SGI Free Software License B v1.0",
+ "licenseId": "SGI-B-1.0",
+ "seeAlso": [
+ "http://oss.sgi.com/projects/FreeB/SGIFreeSWLicB.1.0.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MakeIndex.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MakeIndex.json",
+ "referenceNumber": 123,
+ "name": "MakeIndex License",
+ "licenseId": "MakeIndex",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/MakeIndex"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.1-no-invariants-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.1-no-invariants-only.json",
+ "referenceNumber": 124,
+ "name": "GNU Free Documentation License v1.1 only - no invariants",
+ "licenseId": "GFDL-1.1-no-invariants-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.1.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/TCL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TCL.json",
+ "referenceNumber": 125,
+ "name": "TCL/TK License",
+ "licenseId": "TCL",
+ "seeAlso": [
+ "http://www.tcl.tk/software/tcltk/license.html",
+ "https://fedoraproject.org/wiki/Licensing/TCL"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-Protection.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-Protection.json",
+ "referenceNumber": 126,
+ "name": "BSD Protection License",
+ "licenseId": "BSD-Protection",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/BSD_Protection_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Xdebug-1.03.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Xdebug-1.03.json",
+ "referenceNumber": 127,
+ "name": "Xdebug License v 1.03",
+ "licenseId": "Xdebug-1.03",
+ "seeAlso": [
+ "https://github.com/xdebug/xdebug/blob/master/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-2.5-AU.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-2.5-AU.json",
+ "referenceNumber": 128,
+ "name": "Creative Commons Attribution 2.5 Australia",
+ "licenseId": "CC-BY-2.5-AU",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/2.5/au/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CECILL-C.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CECILL-C.json",
+ "referenceNumber": 129,
+ "name": "CeCILL-C Free Software License Agreement",
+ "licenseId": "CECILL-C",
+ "seeAlso": [
+ "http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-4.3RENO.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-4.3RENO.json",
+ "referenceNumber": 130,
+ "name": "BSD 4.3 RENO License",
+ "licenseId": "BSD-4.3RENO",
+ "seeAlso": [
+ "https://sourceware.org/git/?p\u003dbinutils-gdb.git;a\u003dblob;f\u003dlibiberty/strcasecmp.c;h\u003d131d81c2ce7881fa48c363dc5bf5fb302c61ce0b;hb\u003dHEAD"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Brian-Gladman-3-Clause.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Brian-Gladman-3-Clause.json",
+ "referenceNumber": 131,
+ "name": "Brian Gladman 3-Clause License",
+ "licenseId": "Brian-Gladman-3-Clause",
+ "seeAlso": [
+ "https://github.com/SWI-Prolog/packages-clib/blob/master/sha1/brg_endian.h"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-1.0.json",
+ "referenceNumber": 132,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 1.0 Generic",
+ "licenseId": "CC-BY-NC-SA-1.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/1.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OGTSL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OGTSL.json",
+ "referenceNumber": 133,
+ "name": "Open Group Test Suite License",
+ "licenseId": "OGTSL",
+ "seeAlso": [
+ "http://www.opengroup.org/testing/downloads/The_Open_Group_TSL.txt",
+ "https://opensource.org/licenses/OGTSL"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.7.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.7.json",
+ "referenceNumber": 134,
+ "name": "Open LDAP Public License v2.7",
+ "licenseId": "OLDAP-2.7",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003d47c2415c1df81556eeb39be6cad458ef87c534a2"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/HaskellReport.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/HaskellReport.json",
+ "referenceNumber": 135,
+ "name": "Haskell Language Report License",
+ "licenseId": "HaskellReport",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Haskell_Language_Report_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/RPL-1.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/RPL-1.5.json",
+ "referenceNumber": 136,
+ "name": "Reciprocal Public License 1.5",
+ "licenseId": "RPL-1.5",
+ "seeAlso": [
+ "https://opensource.org/licenses/RPL-1.5"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Unlicense.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Unlicense.json",
+ "referenceNumber": 137,
+ "name": "The Unlicense",
+ "licenseId": "Unlicense",
+ "seeAlso": [
+ "https://unlicense.org/"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/XFree86-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/XFree86-1.1.json",
+ "referenceNumber": 138,
+ "name": "XFree86 License 1.1",
+ "licenseId": "XFree86-1.1",
+ "seeAlso": [
+ "http://www.xfree86.org/current/LICENSE4.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-3.0.json",
+ "referenceNumber": 139,
+ "name": "Creative Commons Attribution Share Alike 3.0 Unported",
+ "licenseId": "CC-BY-SA-3.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/3.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.2.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.2.2.json",
+ "referenceNumber": 140,
+ "name": "Open LDAP Public License 2.2.2",
+ "licenseId": "OLDAP-2.2.2",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003ddf2cc1e21eb7c160695f5b7cffd6296c151ba188"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-3.0-IGO.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-3.0-IGO.json",
+ "referenceNumber": 141,
+ "name": "Creative Commons Attribution 3.0 IGO",
+ "licenseId": "CC-BY-3.0-IGO",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/3.0/igo/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/snprintf.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/snprintf.json",
+ "referenceNumber": 142,
+ "name": "snprintf License",
+ "licenseId": "snprintf",
+ "seeAlso": [
+ "https://github.com/openssh/openssh-portable/blob/master/openbsd-compat/bsd-snprintf.c#L2"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-2.0.json",
+ "referenceNumber": 143,
+ "name": "Creative Commons Attribution Non Commercial 2.0 Generic",
+ "licenseId": "CC-BY-NC-2.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc/2.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/dtoa.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/dtoa.json",
+ "referenceNumber": 144,
+ "name": "David M. Gay dtoa License",
+ "licenseId": "dtoa",
+ "seeAlso": [
+ "https://github.com/SWI-Prolog/swipl-devel/blob/master/src/os/dtoa.c"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MITNFA.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MITNFA.json",
+ "referenceNumber": 145,
+ "name": "MIT +no-false-attribs license",
+ "licenseId": "MITNFA",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/MITNFA"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-3.0+.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-3.0+.json",
+ "referenceNumber": 146,
+ "name": "GNU General Public License v3.0 or later",
+ "licenseId": "GPL-3.0+",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/gpl-3.0-standalone.html",
+ "https://opensource.org/licenses/GPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/AML.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AML.json",
+ "referenceNumber": 147,
+ "name": "Apple MIT License",
+ "licenseId": "AML",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Apple_MIT_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Artistic-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Artistic-2.0.json",
+ "referenceNumber": 148,
+ "name": "Artistic License 2.0",
+ "licenseId": "Artistic-2.0",
+ "seeAlso": [
+ "http://www.perlfoundation.org/artistic_license_2_0",
+ "https://www.perlfoundation.org/artistic-license-20.html",
+ "https://opensource.org/licenses/artistic-license-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CECILL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CECILL-2.0.json",
+ "referenceNumber": 149,
+ "name": "CeCILL Free Software License Agreement v2.0",
+ "licenseId": "CECILL-2.0",
+ "seeAlso": [
+ "http://www.cecill.info/licences/Licence_CeCILL_V2-en.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/App-s2p.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/App-s2p.json",
+ "referenceNumber": 150,
+ "name": "App::s2p License",
+ "licenseId": "App-s2p",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/App-s2p"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SSH-short.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SSH-short.json",
+ "referenceNumber": 151,
+ "name": "SSH short notice",
+ "licenseId": "SSH-short",
+ "seeAlso": [
+ "https://github.com/openssh/openssh-portable/blob/1b11ea7c58cd5c59838b5fa574cd456d6047b2d4/pathnames.h",
+ "http://web.mit.edu/kolya/.f/root/athena.mit.edu/sipb.mit.edu/project/openssh/OldFiles/src/openssh-2.9.9p2/ssh-add.1",
+ "https://joinup.ec.europa.eu/svn/lesoll/trunk/italc/lib/src/dsa_key.cpp"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/AAL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AAL.json",
+ "referenceNumber": 152,
+ "name": "Attribution Assurance License",
+ "licenseId": "AAL",
+ "seeAlso": [
+ "https://opensource.org/licenses/attribution"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/VSL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/VSL-1.0.json",
+ "referenceNumber": 153,
+ "name": "Vovida Software License v1.0",
+ "licenseId": "VSL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/VSL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/AFL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AFL-2.0.json",
+ "referenceNumber": 154,
+ "name": "Academic Free License v2.0",
+ "licenseId": "AFL-2.0",
+ "seeAlso": [
+ "http://wayback.archive.org/web/20060924134533/http://www.opensource.org/licenses/afl-2.0.txt"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OML.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OML.json",
+ "referenceNumber": 155,
+ "name": "Open Market License",
+ "licenseId": "OML",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Open_Market_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-3.0-US.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-3.0-US.json",
+ "referenceNumber": 156,
+ "name": "Creative Commons Attribution 3.0 United States",
+ "licenseId": "CC-BY-3.0-US",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/3.0/us/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/mplus.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/mplus.json",
+ "referenceNumber": 157,
+ "name": "mplus Font License",
+ "licenseId": "mplus",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing:Mplus?rd\u003dLicensing/mplus"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Qhull.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Qhull.json",
+ "referenceNumber": 158,
+ "name": "Qhull License",
+ "licenseId": "Qhull",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Qhull"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/FDK-AAC.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/FDK-AAC.json",
+ "referenceNumber": 159,
+ "name": "Fraunhofer FDK AAC Codec Library",
+ "licenseId": "FDK-AAC",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/FDK-AAC",
+ "https://directory.fsf.org/wiki/License:Fdk"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-4-Clause-UC.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-4-Clause-UC.json",
+ "referenceNumber": 160,
+ "name": "BSD-4-Clause (University of California-Specific)",
+ "licenseId": "BSD-4-Clause-UC",
+ "seeAlso": [
+ "http://www.freebsd.org/copyright/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/PolyForm-Small-Business-1.0.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/PolyForm-Small-Business-1.0.0.json",
+ "referenceNumber": 161,
+ "name": "PolyForm Small Business License 1.0.0",
+ "licenseId": "PolyForm-Small-Business-1.0.0",
+ "seeAlso": [
+ "https://polyformproject.org/licenses/small-business/1.0.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Sleepycat.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Sleepycat.json",
+ "referenceNumber": 162,
+ "name": "Sleepycat License",
+ "licenseId": "Sleepycat",
+ "seeAlso": [
+ "https://opensource.org/licenses/Sleepycat"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.2.json",
+ "referenceNumber": 163,
+ "name": "Open LDAP Public License v2.2",
+ "licenseId": "OLDAP-2.2",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003d470b0c18ec67621c85881b2733057fecf4a1acc3"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Spencer-99.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Spencer-99.json",
+ "referenceNumber": 164,
+ "name": "Spencer License 99",
+ "licenseId": "Spencer-99",
+ "seeAlso": [
+ "http://www.opensource.apple.com/source/tcl/tcl-5/tcl/generic/regfronts.c"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OGL-UK-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OGL-UK-1.0.json",
+ "referenceNumber": 165,
+ "name": "Open Government Licence v1.0",
+ "licenseId": "OGL-UK-1.0",
+ "seeAlso": [
+ "http://www.nationalarchives.gov.uk/doc/open-government-licence/version/1/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/EUPL-1.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EUPL-1.2.json",
+ "referenceNumber": 166,
+ "name": "European Union Public License 1.2",
+ "licenseId": "EUPL-1.2",
+ "seeAlso": [
+ "https://joinup.ec.europa.eu/page/eupl-text-11-12",
+ "https://joinup.ec.europa.eu/sites/default/files/custom-page/attachment/eupl_v1.2_en.pdf",
+ "https://joinup.ec.europa.eu/sites/default/files/custom-page/attachment/2020-03/EUPL-1.2%20EN.txt",
+ "https://joinup.ec.europa.eu/sites/default/files/inline-files/EUPL%20v1_2%20EN(1).txt",
+ "http://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri\u003dCELEX:32017D0863",
+ "https://opensource.org/licenses/EUPL-1.2"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Linux-man-pages-copyleft-2-para.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Linux-man-pages-copyleft-2-para.json",
+ "referenceNumber": 167,
+ "name": "Linux man-pages Copyleft - 2 paragraphs",
+ "licenseId": "Linux-man-pages-copyleft-2-para",
+ "seeAlso": [
+ "https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man2/move_pages.2#n5",
+ "https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man2/migrate_pages.2#n8"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/FreeBSD-DOC.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/FreeBSD-DOC.json",
+ "referenceNumber": 168,
+ "name": "FreeBSD Documentation License",
+ "licenseId": "FreeBSD-DOC",
+ "seeAlso": [
+ "https://www.freebsd.org/copyright/freebsd-doc-license/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/RSCPL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/RSCPL.json",
+ "referenceNumber": 169,
+ "name": "Ricoh Source Code Public License",
+ "licenseId": "RSCPL",
+ "seeAlso": [
+ "http://wayback.archive.org/web/20060715140826/http://www.risource.org/RPL/RPL-1.0A.shtml",
+ "https://opensource.org/licenses/RSCPL"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/eGenix.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/eGenix.json",
+ "referenceNumber": 170,
+ "name": "eGenix.com Public License 1.1.0",
+ "licenseId": "eGenix",
+ "seeAlso": [
+ "http://www.egenix.com/products/eGenix.com-Public-License-1.1.0.pdf",
+ "https://fedoraproject.org/wiki/Licensing/eGenix.com_Public_License_1.1.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-2.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-2.5.json",
+ "referenceNumber": 171,
+ "name": "Creative Commons Attribution 2.5 Generic",
+ "licenseId": "CC-BY-2.5",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/2.5/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/HPND.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/HPND.json",
+ "referenceNumber": 172,
+ "name": "Historical Permission Notice and Disclaimer",
+ "licenseId": "HPND",
+ "seeAlso": [
+ "https://opensource.org/licenses/HPND"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/SCEA.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SCEA.json",
+ "referenceNumber": 173,
+ "name": "SCEA Shared Source License",
+ "licenseId": "SCEA",
+ "seeAlso": [
+ "http://research.scea.com/scea_shared_source_license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-3.0-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GPL-3.0-only.json",
+ "referenceNumber": 174,
+ "name": "GNU General Public License v3.0 only",
+ "licenseId": "GPL-3.0-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/gpl-3.0-standalone.html",
+ "https://opensource.org/licenses/GPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Bitstream-Charter.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Bitstream-Charter.json",
+ "referenceNumber": 175,
+ "name": "Bitstream Charter Font License",
+ "licenseId": "Bitstream-Charter",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Charter#License_Text",
+ "https://raw.githubusercontent.com/blackhole89/notekit/master/data/fonts/Charter%20license.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LAL-1.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LAL-1.2.json",
+ "referenceNumber": 176,
+ "name": "Licence Art Libre 1.2",
+ "licenseId": "LAL-1.2",
+ "seeAlso": [
+ "http://artlibre.org/licence/lal/licence-art-libre-12/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/APSL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/APSL-1.0.json",
+ "referenceNumber": 177,
+ "name": "Apple Public Source License 1.0",
+ "licenseId": "APSL-1.0",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Apple_Public_Source_License_1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Caldera.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Caldera.json",
+ "referenceNumber": 178,
+ "name": "Caldera License",
+ "licenseId": "Caldera",
+ "seeAlso": [
+ "http://www.lemis.com/grog/UNIX/ancient-source-all.pdf"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Xerox.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Xerox.json",
+ "referenceNumber": 179,
+ "name": "Xerox License",
+ "licenseId": "Xerox",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Xerox"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SWL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SWL.json",
+ "referenceNumber": 180,
+ "name": "Scheme Widget Library (SWL) Software License Agreement",
+ "licenseId": "SWL",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/SWL"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MS-LPL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MS-LPL.json",
+ "referenceNumber": 181,
+ "name": "Microsoft Limited Public License",
+ "licenseId": "MS-LPL",
+ "seeAlso": [
+ "https://www.openhub.net/licenses/mslpl",
+ "https://github.com/gabegundy/atlserver/blob/master/License.txt",
+ "https://en.wikipedia.org/wiki/Shared_Source_Initiative#Microsoft_Limited_Public_License_(Ms-LPL)"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Cube.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Cube.json",
+ "referenceNumber": 182,
+ "name": "Cube License",
+ "licenseId": "Cube",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Cube"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/APSL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/APSL-2.0.json",
+ "referenceNumber": 183,
+ "name": "Apple Public Source License 2.0",
+ "licenseId": "APSL-2.0",
+ "seeAlso": [
+ "http://www.opensource.apple.com/license/apsl/"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/APAFML.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/APAFML.json",
+ "referenceNumber": 184,
+ "name": "Adobe Postscript AFM License",
+ "licenseId": "APAFML",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/AdobePostscriptAFM"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Watcom-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Watcom-1.0.json",
+ "referenceNumber": 185,
+ "name": "Sybase Open Watcom Public License 1.0",
+ "licenseId": "Watcom-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/Watcom-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SISSL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SISSL.json",
+ "referenceNumber": 186,
+ "name": "Sun Industry Standards Source License v1.1",
+ "licenseId": "SISSL",
+ "seeAlso": [
+ "http://www.openoffice.org/licenses/sissl_license.html",
+ "https://opensource.org/licenses/SISSL"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CDDL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CDDL-1.0.json",
+ "referenceNumber": 187,
+ "name": "Common Development and Distribution License 1.0",
+ "licenseId": "CDDL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/cddl1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.2.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.2.json",
+ "referenceNumber": 188,
+ "name": "GNU Free Documentation License v1.2",
+ "licenseId": "GFDL-1.2",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.2.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-3.0-AT.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-3.0-AT.json",
+ "referenceNumber": 189,
+ "name": "Creative Commons Attribution Share Alike 3.0 Austria",
+ "licenseId": "CC-BY-SA-3.0-AT",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/3.0/at/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/psfrag.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/psfrag.json",
+ "referenceNumber": 190,
+ "name": "psfrag License",
+ "licenseId": "psfrag",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/psfrag"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/C-UDA-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/C-UDA-1.0.json",
+ "referenceNumber": 191,
+ "name": "Computational Use of Data Agreement v1.0",
+ "licenseId": "C-UDA-1.0",
+ "seeAlso": [
+ "https://github.com/microsoft/Computational-Use-of-Data-Agreement/blob/master/C-UDA-1.0.md",
+ "https://cdla.dev/computational-use-of-data-agreement-v1-0/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MPL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MPL-1.1.json",
+ "referenceNumber": 192,
+ "name": "Mozilla Public License 1.1",
+ "licenseId": "MPL-1.1",
+ "seeAlso": [
+ "http://www.mozilla.org/MPL/MPL-1.1.html",
+ "https://opensource.org/licenses/MPL-1.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-3.0-NL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-3.0-NL.json",
+ "referenceNumber": 193,
+ "name": "Creative Commons Attribution 3.0 Netherlands",
+ "licenseId": "CC-BY-3.0-NL",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/3.0/nl/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.2-invariants-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.2-invariants-only.json",
+ "referenceNumber": 194,
+ "name": "GNU Free Documentation License v1.2 only - invariants",
+ "licenseId": "GFDL-1.2-invariants-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.2.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-Attribution.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-Attribution.json",
+ "referenceNumber": 195,
+ "name": "BSD with attribution",
+ "licenseId": "BSD-3-Clause-Attribution",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/BSD_with_Attribution"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-3.0-DE.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-3.0-DE.json",
+ "referenceNumber": 196,
+ "name": "Creative Commons Attribution Non Commercial 3.0 Germany",
+ "licenseId": "CC-BY-NC-3.0-DE",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc/3.0/de/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.1-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.1-or-later.json",
+ "referenceNumber": 197,
+ "name": "GNU Free Documentation License v1.1 or later",
+ "licenseId": "GFDL-1.1-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.1.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-2.1+.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-2.1+.json",
+ "referenceNumber": 198,
+ "name": "GNU Lesser General Public License v2.1 or later",
+ "licenseId": "LGPL-2.1+",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html",
+ "https://opensource.org/licenses/LGPL-2.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NCSA.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NCSA.json",
+ "referenceNumber": 199,
+ "name": "University of Illinois/NCSA Open Source License",
+ "licenseId": "NCSA",
+ "seeAlso": [
+ "http://otm.illinois.edu/uiuc_openSource",
+ "https://opensource.org/licenses/NCSA"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-1-Clause.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-1-Clause.json",
+ "referenceNumber": 200,
+ "name": "BSD 1-Clause License",
+ "licenseId": "BSD-1-Clause",
+ "seeAlso": [
+ "https://svnweb.freebsd.org/base/head/include/ifaddrs.h?revision\u003d326823"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/ANTLR-PD-fallback.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ANTLR-PD-fallback.json",
+ "referenceNumber": 201,
+ "name": "ANTLR Software Rights Notice with license fallback",
+ "licenseId": "ANTLR-PD-fallback",
+ "seeAlso": [
+ "http://www.antlr2.org/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-Modification.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-Modification.json",
+ "referenceNumber": 202,
+ "name": "BSD 3-Clause Modification",
+ "licenseId": "BSD-3-Clause-Modification",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing:BSD#Modification_Variant"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/COIL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/COIL-1.0.json",
+ "referenceNumber": 203,
+ "name": "Copyfree Open Innovation License",
+ "licenseId": "COIL-1.0",
+ "seeAlso": [
+ "https://coil.apotheon.org/plaintext/01.0.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/UPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/UPL-1.0.json",
+ "referenceNumber": 204,
+ "name": "Universal Permissive License v1.0",
+ "licenseId": "UPL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/UPL"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-1.0.json",
+ "referenceNumber": 205,
+ "name": "Creative Commons Attribution 1.0 Generic",
+ "licenseId": "CC-BY-1.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/1.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Leptonica.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Leptonica.json",
+ "referenceNumber": 206,
+ "name": "Leptonica License",
+ "licenseId": "Leptonica",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Leptonica"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Frameworx-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Frameworx-1.0.json",
+ "referenceNumber": 207,
+ "name": "Frameworx Open License 1.0",
+ "licenseId": "Frameworx-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/Frameworx-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-1.1.json",
+ "referenceNumber": 208,
+ "name": "Open LDAP Public License v1.1",
+ "licenseId": "OLDAP-1.1",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003d806557a5ad59804ef3a44d5abfbe91d706b0791f"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/FTL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/FTL.json",
+ "referenceNumber": 209,
+ "name": "Freetype Project License",
+ "licenseId": "FTL",
+ "seeAlso": [
+ "http://freetype.fis.uniroma2.it/FTL.TXT",
+ "http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/docs/FTL.TXT",
+ "http://gitlab.freedesktop.org/freetype/freetype/-/raw/master/docs/FTL.TXT"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Artistic-1.0-cl8.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Artistic-1.0-cl8.json",
+ "referenceNumber": 210,
+ "name": "Artistic License 1.0 w/clause 8",
+ "licenseId": "Artistic-1.0-cl8",
+ "seeAlso": [
+ "https://opensource.org/licenses/Artistic-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-ND-3.0-IGO.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-ND-3.0-IGO.json",
+ "referenceNumber": 211,
+ "name": "Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO",
+ "licenseId": "CC-BY-NC-ND-3.0-IGO",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-nd/3.0/igo/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-1.0.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-1.0.json",
+ "referenceNumber": 212,
+ "name": "GNU General Public License v1.0 only",
+ "licenseId": "GPL-1.0",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/gpl-1.0-standalone.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-3.0-IGO.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-3.0-IGO.json",
+ "referenceNumber": 213,
+ "name": "Creative Commons Attribution-ShareAlike 3.0 IGO",
+ "licenseId": "CC-BY-SA-3.0-IGO",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/3.0/igo/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OGL-Canada-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OGL-Canada-2.0.json",
+ "referenceNumber": 214,
+ "name": "Open Government Licence - Canada",
+ "licenseId": "OGL-Canada-2.0",
+ "seeAlso": [
+ "https://open.canada.ca/en/open-government-licence-canada"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/YPL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/YPL-1.1.json",
+ "referenceNumber": 215,
+ "name": "Yahoo! Public License v1.1",
+ "licenseId": "YPL-1.1",
+ "seeAlso": [
+ "http://www.zimbra.com/license/yahoo_public_license_1.1.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-3.0.json",
+ "referenceNumber": 216,
+ "name": "Creative Commons Attribution Non Commercial 3.0 Unported",
+ "licenseId": "CC-BY-NC-3.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc/3.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/AGPL-3.0-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AGPL-3.0-or-later.json",
+ "referenceNumber": 217,
+ "name": "GNU Affero General Public License v3.0 or later",
+ "licenseId": "AGPL-3.0-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/agpl.txt",
+ "https://opensource.org/licenses/AGPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/SSPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SSPL-1.0.json",
+ "referenceNumber": 218,
+ "name": "Server Side Public License, v 1",
+ "licenseId": "SSPL-1.0",
+ "seeAlso": [
+ "https://www.mongodb.com/licensing/server-side-public-license"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-1.0+.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-1.0+.json",
+ "referenceNumber": 219,
+ "name": "GNU General Public License v1.0 or later",
+ "licenseId": "GPL-1.0+",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/gpl-1.0-standalone.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/IPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/IPL-1.0.json",
+ "referenceNumber": 220,
+ "name": "IBM Public License v1.0",
+ "licenseId": "IPL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/IPL-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/TPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TPL-1.0.json",
+ "referenceNumber": 221,
+ "name": "THOR Public License 1.0",
+ "licenseId": "TPL-1.0",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing:ThorPublicLicense"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Knuth-CTAN.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Knuth-CTAN.json",
+ "referenceNumber": 222,
+ "name": "Knuth CTAN License",
+ "licenseId": "Knuth-CTAN",
+ "seeAlso": [
+ "https://ctan.org/license/knuth"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT.json",
+ "referenceNumber": 223,
+ "name": "MIT License",
+ "licenseId": "MIT",
+ "seeAlso": [
+ "https://opensource.org/licenses/MIT"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Rdisc.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Rdisc.json",
+ "referenceNumber": 224,
+ "name": "Rdisc License",
+ "licenseId": "Rdisc",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Rdisc_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Abstyles.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Abstyles.json",
+ "referenceNumber": 225,
+ "name": "Abstyles License",
+ "licenseId": "Abstyles",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Abstyles"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CECILL-2.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CECILL-2.1.json",
+ "referenceNumber": 226,
+ "name": "CeCILL Free Software License Agreement v2.1",
+ "licenseId": "CECILL-2.1",
+ "seeAlso": [
+ "http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/libtiff.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/libtiff.json",
+ "referenceNumber": 227,
+ "name": "libtiff License",
+ "licenseId": "libtiff",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/libtiff"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ErlPL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ErlPL-1.1.json",
+ "referenceNumber": 228,
+ "name": "Erlang Public License v1.1",
+ "licenseId": "ErlPL-1.1",
+ "seeAlso": [
+ "http://www.erlang.org/EPLICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Kazlib.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Kazlib.json",
+ "referenceNumber": 229,
+ "name": "Kazlib License",
+ "licenseId": "Kazlib",
+ "seeAlso": [
+ "http://git.savannah.gnu.org/cgit/kazlib.git/tree/except.c?id\u003d0062df360c2d17d57f6af19b0e444c51feb99036"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/RPSL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/RPSL-1.0.json",
+ "referenceNumber": 230,
+ "name": "RealNetworks Public Source License v1.0",
+ "licenseId": "RPSL-1.0",
+ "seeAlso": [
+ "https://helixcommunity.org/content/rpsl",
+ "https://opensource.org/licenses/RPSL-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-3.0+.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-3.0+.json",
+ "referenceNumber": 231,
+ "name": "GNU Lesser General Public License v3.0 or later",
+ "licenseId": "LGPL-3.0+",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/lgpl-3.0-standalone.html",
+ "https://www.gnu.org/licenses/lgpl+gpl-3.0.txt",
+ "https://opensource.org/licenses/LGPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/AGPL-3.0.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/AGPL-3.0.json",
+ "referenceNumber": 232,
+ "name": "GNU Affero General Public License v3.0",
+ "licenseId": "AGPL-3.0",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/agpl.txt",
+ "https://opensource.org/licenses/AGPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-Clear.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-Clear.json",
+ "referenceNumber": 233,
+ "name": "BSD 3-Clause Clear License",
+ "licenseId": "BSD-3-Clause-Clear",
+ "seeAlso": [
+ "http://labs.metacarta.com/license-explanation.html#license"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-feh.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-feh.json",
+ "referenceNumber": 234,
+ "name": "feh License",
+ "licenseId": "MIT-feh",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/MIT#feh"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-1.0-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GPL-1.0-only.json",
+ "referenceNumber": 235,
+ "name": "GNU General Public License v1.0 only",
+ "licenseId": "GPL-1.0-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/gpl-1.0-standalone.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MPL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MPL-2.0.json",
+ "referenceNumber": 236,
+ "name": "Mozilla Public License 2.0",
+ "licenseId": "MPL-2.0",
+ "seeAlso": [
+ "https://www.mozilla.org/MPL/2.0/",
+ "https://opensource.org/licenses/MPL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LPPL-1.3c.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LPPL-1.3c.json",
+ "referenceNumber": 237,
+ "name": "LaTeX Project Public License v1.3c",
+ "licenseId": "LPPL-1.3c",
+ "seeAlso": [
+ "http://www.latex-project.org/lppl/lppl-1-3c.txt",
+ "https://opensource.org/licenses/LPPL-1.3c"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CDLA-Permissive-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CDLA-Permissive-1.0.json",
+ "referenceNumber": 238,
+ "name": "Community Data License Agreement Permissive 1.0",
+ "licenseId": "CDLA-Permissive-1.0",
+ "seeAlso": [
+ "https://cdla.io/permissive-1-0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Xfig.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Xfig.json",
+ "referenceNumber": 239,
+ "name": "Xfig License",
+ "licenseId": "Xfig",
+ "seeAlso": [
+ "https://github.com/Distrotech/transfig/blob/master/transfig/transfig.c",
+ "https://fedoraproject.org/wiki/Licensing:MIT#Xfig_Variant",
+ "https://sourceforge.net/p/mcj/xfig/ci/master/tree/src/Makefile.am"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-PDDC.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-PDDC.json",
+ "referenceNumber": 240,
+ "name": "Creative Commons Public Domain Dedication and Certification",
+ "licenseId": "CC-PDDC",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/publicdomain/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Inner-Net-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Inner-Net-2.0.json",
+ "referenceNumber": 241,
+ "name": "Inner Net License v2.0",
+ "licenseId": "Inner-Net-2.0",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Inner_Net_License",
+ "https://sourceware.org/git/?p\u003dglibc.git;a\u003dblob;f\u003dLICENSES;h\u003d530893b1dc9ea00755603c68fb36bd4fc38a7be8;hb\u003dHEAD#l207"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ECL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ECL-1.0.json",
+ "referenceNumber": 242,
+ "name": "Educational Community License v1.0",
+ "licenseId": "ECL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/ECL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/SMLNJ.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SMLNJ.json",
+ "referenceNumber": 243,
+ "name": "Standard ML of New Jersey License",
+ "licenseId": "SMLNJ",
+ "seeAlso": [
+ "https://www.smlnj.org/license.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.2-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.2-only.json",
+ "referenceNumber": 244,
+ "name": "GNU Free Documentation License v1.2 only",
+ "licenseId": "GFDL-1.2-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.2.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/bzip2-1.0.5.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/bzip2-1.0.5.json",
+ "referenceNumber": 245,
+ "name": "bzip2 and libbzip2 License v1.0.5",
+ "licenseId": "bzip2-1.0.5",
+ "seeAlso": [
+ "https://sourceware.org/bzip2/1.0.5/bzip2-manual-1.0.5.html",
+ "http://bzip.org/1.0.5/bzip2-manual-1.0.5.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ECL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ECL-2.0.json",
+ "referenceNumber": 246,
+ "name": "Educational Community License v2.0",
+ "licenseId": "ECL-2.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/ECL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Multics.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Multics.json",
+ "referenceNumber": 247,
+ "name": "Multics License",
+ "licenseId": "Multics",
+ "seeAlso": [
+ "https://opensource.org/licenses/Multics"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-4.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-4.0.json",
+ "referenceNumber": 248,
+ "name": "Creative Commons Attribution Non Commercial 4.0 International",
+ "licenseId": "CC-BY-NC-4.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc/4.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.3-no-invariants-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.3-no-invariants-only.json",
+ "referenceNumber": 249,
+ "name": "GNU Free Documentation License v1.3 only - no invariants",
+ "licenseId": "GFDL-1.3-no-invariants-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/fdl-1.3.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OFL-1.0-RFN.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OFL-1.0-RFN.json",
+ "referenceNumber": 250,
+ "name": "SIL Open Font License 1.0 with Reserved Font Name",
+ "licenseId": "OFL-1.0-RFN",
+ "seeAlso": [
+ "http://scripts.sil.org/cms/scripts/page.php?item_id\u003dOFL10_web"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OSL-2.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OSL-2.1.json",
+ "referenceNumber": 251,
+ "name": "Open Software License 2.1",
+ "licenseId": "OSL-2.1",
+ "seeAlso": [
+ "http://web.archive.org/web/20050212003940/http://www.rosenlaw.com/osl21.htm",
+ "https://opensource.org/licenses/OSL-2.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-2.0.json",
+ "referenceNumber": 252,
+ "name": "Creative Commons Attribution Share Alike 2.0 Generic",
+ "licenseId": "CC-BY-SA-2.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/2.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CATOSL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CATOSL-1.1.json",
+ "referenceNumber": 253,
+ "name": "Computer Associates Trusted Open Source License 1.1",
+ "licenseId": "CATOSL-1.1",
+ "seeAlso": [
+ "https://opensource.org/licenses/CATOSL-1.1"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/ICU.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ICU.json",
+ "referenceNumber": 254,
+ "name": "ICU License",
+ "licenseId": "ICU",
+ "seeAlso": [
+ "http://source.icu-project.org/repos/icu/icu/trunk/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BUSL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BUSL-1.1.json",
+ "referenceNumber": 255,
+ "name": "Business Source License 1.1",
+ "licenseId": "BUSL-1.1",
+ "seeAlso": [
+ "https://mariadb.com/bsl11/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/AGPL-1.0.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/AGPL-1.0.json",
+ "referenceNumber": 256,
+ "name": "Affero General Public License v1.0",
+ "licenseId": "AGPL-1.0",
+ "seeAlso": [
+ "http://www.affero.org/oagpl.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OPL-UK-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OPL-UK-3.0.json",
+ "referenceNumber": 257,
+ "name": "United Kingdom Open Parliament Licence v3.0",
+ "licenseId": "OPL-UK-3.0",
+ "seeAlso": [
+ "https://www.parliament.uk/site-information/copyright-parliament/open-parliament-licence/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/copyleft-next-0.3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/copyleft-next-0.3.0.json",
+ "referenceNumber": 258,
+ "name": "copyleft-next 0.3.0",
+ "licenseId": "copyleft-next-0.3.0",
+ "seeAlso": [
+ "https://github.com/copyleft-next/copyleft-next/blob/master/Releases/copyleft-next-0.3.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Symlinks.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Symlinks.json",
+ "referenceNumber": 259,
+ "name": "Symlinks License",
+ "licenseId": "Symlinks",
+ "seeAlso": [
+ "https://www.mail-archive.com/debian-bugs-rc@lists.debian.org/msg11494.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Crossword.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Crossword.json",
+ "referenceNumber": 260,
+ "name": "Crossword License",
+ "licenseId": "Crossword",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Crossword"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0-with-classpath-exception.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0-with-classpath-exception.json",
+ "referenceNumber": 261,
+ "name": "GNU General Public License v2.0 w/Classpath exception",
+ "licenseId": "GPL-2.0-with-classpath-exception",
+ "seeAlso": [
+ "https://www.gnu.org/software/classpath/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/DOC.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/DOC.json",
+ "referenceNumber": 262,
+ "name": "DOC License",
+ "licenseId": "DOC",
+ "seeAlso": [
+ "http://www.cs.wustl.edu/~schmidt/ACE-copying.html",
+ "https://www.dre.vanderbilt.edu/~schmidt/ACE-copying.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ISC.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ISC.json",
+ "referenceNumber": 263,
+ "name": "ISC License",
+ "licenseId": "ISC",
+ "seeAlso": [
+ "https://www.isc.org/licenses/",
+ "https://www.isc.org/downloads/software-support-policy/isc-license/",
+ "https://opensource.org/licenses/ISC"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Apache-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Apache-2.0.json",
+ "referenceNumber": 264,
+ "name": "Apache License 2.0",
+ "licenseId": "Apache-2.0",
+ "seeAlso": [
+ "https://www.apache.org/licenses/LICENSE-2.0",
+ "https://opensource.org/licenses/Apache-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/copyleft-next-0.3.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/copyleft-next-0.3.1.json",
+ "referenceNumber": 265,
+ "name": "copyleft-next 0.3.1",
+ "licenseId": "copyleft-next-0.3.1",
+ "seeAlso": [
+ "https://github.com/copyleft-next/copyleft-next/blob/master/Releases/copyleft-next-0.3.1"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ASWF-Digital-Assets-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ASWF-Digital-Assets-1.1.json",
+ "referenceNumber": 266,
+ "name": "ASWF Digital Assets License 1.1",
+ "licenseId": "ASWF-Digital-Assets-1.1",
+ "seeAlso": [
+ "https://github.com/AcademySoftwareFoundation/foundation/blob/main/digital_assets/aswf_digital_assets_license_v1.1.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SISSL-1.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SISSL-1.2.json",
+ "referenceNumber": 267,
+ "name": "Sun Industry Standards Source License v1.2",
+ "licenseId": "SISSL-1.2",
+ "seeAlso": [
+ "http://gridscheduler.sourceforge.net/Gridengine_SISSL_license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Unicode-TOU.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Unicode-TOU.json",
+ "referenceNumber": 268,
+ "name": "Unicode Terms of Use",
+ "licenseId": "Unicode-TOU",
+ "seeAlso": [
+ "http://web.archive.org/web/20140704074106/http://www.unicode.org/copyright.html",
+ "http://www.unicode.org/copyright.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-2-Clause.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-2-Clause.json",
+ "referenceNumber": 269,
+ "name": "BSD 2-Clause \"Simplified\" License",
+ "licenseId": "BSD-2-Clause",
+ "seeAlso": [
+ "https://opensource.org/licenses/BSD-2-Clause"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CDLA-Permissive-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CDLA-Permissive-2.0.json",
+ "referenceNumber": 270,
+ "name": "Community Data License Agreement Permissive 2.0",
+ "licenseId": "CDLA-Permissive-2.0",
+ "seeAlso": [
+ "https://cdla.dev/permissive-2-0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-3.0.json",
+ "referenceNumber": 271,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 3.0 Unported",
+ "licenseId": "CC-BY-NC-SA-3.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/3.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/HPND-export-US.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/HPND-export-US.json",
+ "referenceNumber": 272,
+ "name": "HPND with US Government export control warning",
+ "licenseId": "HPND-export-US",
+ "seeAlso": [
+ "https://www.kermitproject.org/ck90.html#source"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/etalab-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/etalab-2.0.json",
+ "referenceNumber": 273,
+ "name": "Etalab Open License 2.0",
+ "licenseId": "etalab-2.0",
+ "seeAlso": [
+ "https://github.com/DISIC/politique-de-contribution-open-source/blob/master/LICENSE.pdf",
+ "https://raw.githubusercontent.com/DISIC/politique-de-contribution-open-source/master/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OSET-PL-2.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OSET-PL-2.1.json",
+ "referenceNumber": 274,
+ "name": "OSET Public License version 2.1",
+ "licenseId": "OSET-PL-2.1",
+ "seeAlso": [
+ "http://www.osetfoundation.org/public-license",
+ "https://opensource.org/licenses/OPL-2.1"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.1-invariants-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.1-invariants-or-later.json",
+ "referenceNumber": 275,
+ "name": "GNU Free Documentation License v1.1 or later - invariants",
+ "licenseId": "GFDL-1.1-invariants-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.1.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OpenSSL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OpenSSL.json",
+ "referenceNumber": 276,
+ "name": "OpenSSL License",
+ "licenseId": "OpenSSL",
+ "seeAlso": [
+ "http://www.openssl.org/source/license.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/ASWF-Digital-Assets-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ASWF-Digital-Assets-1.0.json",
+ "referenceNumber": 277,
+ "name": "ASWF Digital Assets License version 1.0",
+ "licenseId": "ASWF-Digital-Assets-1.0",
+ "seeAlso": [
+ "https://github.com/AcademySoftwareFoundation/foundation/blob/main/digital_assets/aswf_digital_assets_license_v1.0.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SGI-B-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SGI-B-2.0.json",
+ "referenceNumber": 278,
+ "name": "SGI Free Software License B v2.0",
+ "licenseId": "SGI-B-2.0",
+ "seeAlso": [
+ "http://oss.sgi.com/projects/FreeB/SGIFreeSWLicB.2.0.pdf"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC0-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC0-1.0.json",
+ "referenceNumber": 279,
+ "name": "Creative Commons Zero v1.0 Universal",
+ "licenseId": "CC0-1.0",
+ "seeAlso": [
+ "https://creativecommons.org/publicdomain/zero/1.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-Attribution-HPND-disclaimer.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-Attribution-HPND-disclaimer.json",
+ "referenceNumber": 280,
+ "name": "BSD with Attribution and HPND disclaimer",
+ "licenseId": "BSD-Attribution-HPND-disclaimer",
+ "seeAlso": [
+ "https://github.com/cyrusimap/cyrus-sasl/blob/master/COPYING"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/mpich2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/mpich2.json",
+ "referenceNumber": 281,
+ "name": "mpich2 License",
+ "licenseId": "mpich2",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/MIT"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Artistic-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Artistic-1.0.json",
+ "referenceNumber": 282,
+ "name": "Artistic License 1.0",
+ "licenseId": "Artistic-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/Artistic-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.3-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.3-only.json",
+ "referenceNumber": 283,
+ "name": "GNU Free Documentation License v1.3 only",
+ "licenseId": "GFDL-1.3-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/fdl-1.3.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OGDL-Taiwan-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OGDL-Taiwan-1.0.json",
+ "referenceNumber": 284,
+ "name": "Taiwan Open Government Data License, version 1.0",
+ "licenseId": "OGDL-Taiwan-1.0",
+ "seeAlso": [
+ "https://data.gov.tw/license"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.2-no-invariants-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.2-no-invariants-or-later.json",
+ "referenceNumber": 285,
+ "name": "GNU Free Documentation License v1.2 or later - no invariants",
+ "licenseId": "GFDL-1.2-no-invariants-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.2.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LiLiQ-Rplus-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LiLiQ-Rplus-1.1.json",
+ "referenceNumber": 286,
+ "name": "Licence Libre du Québec – Réciprocité forte version 1.1",
+ "licenseId": "LiLiQ-Rplus-1.1",
+ "seeAlso": [
+ "https://www.forge.gouv.qc.ca/participez/licence-logicielle/licence-libre-du-quebec-liliq-en-francais/licence-libre-du-quebec-reciprocite-forte-liliq-r-v1-1/",
+ "http://opensource.org/licenses/LiLiQ-Rplus-1.1"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/ImageMagick.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ImageMagick.json",
+ "referenceNumber": 287,
+ "name": "ImageMagick License",
+ "licenseId": "ImageMagick",
+ "seeAlso": [
+ "http://www.imagemagick.org/script/license.php"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/X11-distribute-modifications-variant.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/X11-distribute-modifications-variant.json",
+ "referenceNumber": 288,
+ "name": "X11 License Distribution Modification Variant",
+ "licenseId": "X11-distribute-modifications-variant",
+ "seeAlso": [
+ "https://github.com/mirror/ncurses/blob/master/COPYING"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/dvipdfm.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/dvipdfm.json",
+ "referenceNumber": 289,
+ "name": "dvipdfm License",
+ "licenseId": "dvipdfm",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/dvipdfm"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MulanPSL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MulanPSL-1.0.json",
+ "referenceNumber": 290,
+ "name": "Mulan Permissive Software License, Version 1",
+ "licenseId": "MulanPSL-1.0",
+ "seeAlso": [
+ "https://license.coscl.org.cn/MulanPSL/",
+ "https://github.com/yuwenlong/longphp/blob/25dfb70cc2a466dc4bb55ba30901cbce08d164b5/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Unicode-DFS-2015.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Unicode-DFS-2015.json",
+ "referenceNumber": 291,
+ "name": "Unicode License Agreement - Data Files and Software (2015)",
+ "licenseId": "Unicode-DFS-2015",
+ "seeAlso": [
+ "https://web.archive.org/web/20151224134844/http://unicode.org/copyright.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-1.0.json",
+ "referenceNumber": 292,
+ "name": "Creative Commons Attribution Non Commercial 1.0 Generic",
+ "licenseId": "CC-BY-NC-1.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc/1.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-3.0-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-3.0-or-later.json",
+ "referenceNumber": 293,
+ "name": "GNU Lesser General Public License v3.0 or later",
+ "licenseId": "LGPL-3.0-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/lgpl-3.0-standalone.html",
+ "https://www.gnu.org/licenses/lgpl+gpl-3.0.txt",
+ "https://opensource.org/licenses/LGPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GD.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GD.json",
+ "referenceNumber": 294,
+ "name": "GD License",
+ "licenseId": "GD",
+ "seeAlso": [
+ "https://libgd.github.io/manuals/2.3.0/files/license-txt.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/mpi-permissive.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/mpi-permissive.json",
+ "referenceNumber": 295,
+ "name": "mpi Permissive License",
+ "licenseId": "mpi-permissive",
+ "seeAlso": [
+ "https://sources.debian.org/src/openmpi/4.1.0-10/ompi/debuggers/msgq_interface.h/?hl\u003d19#L19"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0-with-autoconf-exception.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0-with-autoconf-exception.json",
+ "referenceNumber": 296,
+ "name": "GNU General Public License v2.0 w/Autoconf exception",
+ "licenseId": "GPL-2.0-with-autoconf-exception",
+ "seeAlso": [
+ "http://ac-archive.sourceforge.net/doc/copyright.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.6.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.6.json",
+ "referenceNumber": 297,
+ "name": "Open LDAP Public License v2.6",
+ "licenseId": "OLDAP-2.6",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003d1cae062821881f41b73012ba816434897abf4205"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-3.0.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-3.0.json",
+ "referenceNumber": 298,
+ "name": "GNU Lesser General Public License v3.0 only",
+ "licenseId": "LGPL-3.0",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/lgpl-3.0-standalone.html",
+ "https://www.gnu.org/licenses/lgpl+gpl-3.0.txt",
+ "https://opensource.org/licenses/LGPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/StandardML-NJ.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/StandardML-NJ.json",
+ "referenceNumber": 299,
+ "name": "Standard ML of New Jersey License",
+ "licenseId": "StandardML-NJ",
+ "seeAlso": [
+ "https://www.smlnj.org/license.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Minpack.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Minpack.json",
+ "referenceNumber": 300,
+ "name": "Minpack License",
+ "licenseId": "Minpack",
+ "seeAlso": [
+ "http://www.netlib.org/minpack/disclaimer",
+ "https://gitlab.com/libeigen/eigen/-/blob/master/COPYING.MINPACK"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NGPL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NGPL.json",
+ "referenceNumber": 301,
+ "name": "Nethack General Public License",
+ "licenseId": "NGPL",
+ "seeAlso": [
+ "https://opensource.org/licenses/NGPL"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/diffmark.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/diffmark.json",
+ "referenceNumber": 302,
+ "name": "diffmark license",
+ "licenseId": "diffmark",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/diffmark"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Latex2e.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Latex2e.json",
+ "referenceNumber": 303,
+ "name": "Latex2e License",
+ "licenseId": "Latex2e",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Latex2e"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OGL-UK-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OGL-UK-2.0.json",
+ "referenceNumber": 304,
+ "name": "Open Government Licence v2.0",
+ "licenseId": "OGL-UK-2.0",
+ "seeAlso": [
+ "http://www.nationalarchives.gov.uk/doc/open-government-licence/version/2/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/AFL-2.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AFL-2.1.json",
+ "referenceNumber": 305,
+ "name": "Academic Free License v2.1",
+ "licenseId": "AFL-2.1",
+ "seeAlso": [
+ "http://opensource.linux-mirror.org/licenses/afl-2.1.txt"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/AFL-1.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AFL-1.2.json",
+ "referenceNumber": 306,
+ "name": "Academic Free License v1.2",
+ "licenseId": "AFL-1.2",
+ "seeAlso": [
+ "http://opensource.linux-mirror.org/licenses/afl-1.2.txt",
+ "http://wayback.archive.org/web/20021204204652/http://www.opensource.org/licenses/academic.php"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Python-2.0.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Python-2.0.1.json",
+ "referenceNumber": 307,
+ "name": "Python License 2.0.1",
+ "licenseId": "Python-2.0.1",
+ "seeAlso": [
+ "https://www.python.org/download/releases/2.0.1/license/",
+ "https://docs.python.org/3/license.html",
+ "https://github.com/python/cpython/blob/main/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CECILL-B.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CECILL-B.json",
+ "referenceNumber": 308,
+ "name": "CeCILL-B Free Software License Agreement",
+ "licenseId": "CECILL-B",
+ "seeAlso": [
+ "http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OCCT-PL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OCCT-PL.json",
+ "referenceNumber": 309,
+ "name": "Open CASCADE Technology Public License",
+ "licenseId": "OCCT-PL",
+ "seeAlso": [
+ "http://www.opencascade.com/content/occt-public-license"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OSL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OSL-1.1.json",
+ "referenceNumber": 310,
+ "name": "Open Software License 1.1",
+ "licenseId": "OSL-1.1",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/OSL1.1"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Spencer-86.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Spencer-86.json",
+ "referenceNumber": 311,
+ "name": "Spencer License 86",
+ "licenseId": "Spencer-86",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Henry_Spencer_Reg-Ex_Library_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/xinetd.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/xinetd.json",
+ "referenceNumber": 312,
+ "name": "xinetd License",
+ "licenseId": "xinetd",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Xinetd_License"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.2-invariants-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.2-invariants-or-later.json",
+ "referenceNumber": 313,
+ "name": "GNU Free Documentation License v1.2 or later - invariants",
+ "licenseId": "GFDL-1.2-invariants-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.2.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Boehm-GC.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Boehm-GC.json",
+ "referenceNumber": 314,
+ "name": "Boehm-Demers-Weiser GC License",
+ "licenseId": "Boehm-GC",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing:MIT#Another_Minimal_variant_(found_in_libatomic_ops)",
+ "https://github.com/uim/libgcroots/blob/master/COPYING",
+ "https://github.com/ivmai/libatomic_ops/blob/master/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Graphics-Gems.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Graphics-Gems.json",
+ "referenceNumber": 315,
+ "name": "Graphics Gems License",
+ "licenseId": "Graphics-Gems",
+ "seeAlso": [
+ "https://github.com/erich666/GraphicsGems/blob/master/LICENSE.md"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CAL-1.0-Combined-Work-Exception.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CAL-1.0-Combined-Work-Exception.json",
+ "referenceNumber": 316,
+ "name": "Cryptographic Autonomy License 1.0 (Combined Work Exception)",
+ "licenseId": "CAL-1.0-Combined-Work-Exception",
+ "seeAlso": [
+ "http://cryptographicautonomylicense.com/license-text.html",
+ "https://opensource.org/licenses/CAL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-3.0-DE.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-3.0-DE.json",
+ "referenceNumber": 317,
+ "name": "Creative Commons Attribution 3.0 Germany",
+ "licenseId": "CC-BY-3.0-DE",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/3.0/de/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GLWTPL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GLWTPL.json",
+ "referenceNumber": 318,
+ "name": "Good Luck With That Public License",
+ "licenseId": "GLWTPL",
+ "seeAlso": [
+ "https://github.com/me-shaon/GLWTPL/commit/da5f6bc734095efbacb442c0b31e33a65b9d6e85"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NIST-PD-fallback.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NIST-PD-fallback.json",
+ "referenceNumber": 319,
+ "name": "NIST Public Domain Notice with license fallback",
+ "licenseId": "NIST-PD-fallback",
+ "seeAlso": [
+ "https://github.com/usnistgov/jsip/blob/59700e6926cbe96c5cdae897d9a7d2656b42abe3/LICENSE",
+ "https://github.com/usnistgov/fipy/blob/86aaa5c2ba2c6f1be19593c5986071cf6568cc34/LICENSE.rst"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause.json",
+ "referenceNumber": 320,
+ "name": "BSD 3-Clause \"New\" or \"Revised\" License",
+ "licenseId": "BSD-3-Clause",
+ "seeAlso": [
+ "https://opensource.org/licenses/BSD-3-Clause",
+ "https://www.eclipse.org/org/documents/edl-v10.php"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NetCDF.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NetCDF.json",
+ "referenceNumber": 321,
+ "name": "NetCDF license",
+ "licenseId": "NetCDF",
+ "seeAlso": [
+ "http://www.unidata.ucar.edu/software/netcdf/copyright.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-ND-3.0-DE.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-ND-3.0-DE.json",
+ "referenceNumber": 322,
+ "name": "Creative Commons Attribution No Derivatives 3.0 Germany",
+ "licenseId": "CC-BY-ND-3.0-DE",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nd/3.0/de/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Parity-7.0.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Parity-7.0.0.json",
+ "referenceNumber": 323,
+ "name": "The Parity Public License 7.0.0",
+ "licenseId": "Parity-7.0.0",
+ "seeAlso": [
+ "https://paritylicense.com/versions/7.0.0.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.0.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.0.1.json",
+ "referenceNumber": 324,
+ "name": "Open LDAP Public License v2.0.1",
+ "licenseId": "OLDAP-2.0.1",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003db6d68acd14e51ca3aab4428bf26522aa74873f0e"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/DRL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/DRL-1.0.json",
+ "referenceNumber": 325,
+ "name": "Detection Rule License 1.0",
+ "licenseId": "DRL-1.0",
+ "seeAlso": [
+ "https://github.com/Neo23x0/sigma/blob/master/LICENSE.Detection.Rules.md"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/TU-Berlin-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TU-Berlin-2.0.json",
+ "referenceNumber": 326,
+ "name": "Technische Universitaet Berlin License 2.0",
+ "licenseId": "TU-Berlin-2.0",
+ "seeAlso": [
+ "https://github.com/CorsixTH/deps/blob/fd339a9f526d1d9c9f01ccf39e438a015da50035/licences/libgsm.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Borceux.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Borceux.json",
+ "referenceNumber": 327,
+ "name": "Borceux license",
+ "licenseId": "Borceux",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Borceux"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-1.3.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-1.3.json",
+ "referenceNumber": 328,
+ "name": "Open LDAP Public License v1.3",
+ "licenseId": "OLDAP-1.3",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003de5f8117f0ce088d0bd7a8e18ddf37eaa40eb09b1"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Giftware.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Giftware.json",
+ "referenceNumber": 329,
+ "name": "Giftware License",
+ "licenseId": "Giftware",
+ "seeAlso": [
+ "http://liballeg.org/license.html#allegro-4-the-giftware-license"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SGI-B-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SGI-B-1.1.json",
+ "referenceNumber": 330,
+ "name": "SGI Free Software License B v1.1",
+ "licenseId": "SGI-B-1.1",
+ "seeAlso": [
+ "http://oss.sgi.com/projects/FreeB/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License.json",
+ "referenceNumber": 331,
+ "name": "BSD 3-Clause No Nuclear License",
+ "licenseId": "BSD-3-Clause-No-Nuclear-License",
+ "seeAlso": [
+ "http://download.oracle.com/otn-pub/java/licenses/bsd.txt?AuthParam\u003d1467140197_43d516ce1776bd08a58235a7785be1cc"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/curl.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/curl.json",
+ "referenceNumber": 332,
+ "name": "curl License",
+ "licenseId": "curl",
+ "seeAlso": [
+ "https://github.com/bagder/curl/blob/master/COPYING"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-1.4.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-1.4.json",
+ "referenceNumber": 333,
+ "name": "Open LDAP Public License v1.4",
+ "licenseId": "OLDAP-1.4",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003dc9f95c2f3f2ffb5e0ae55fe7388af75547660941"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SNIA.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SNIA.json",
+ "referenceNumber": 334,
+ "name": "SNIA Public License 1.1",
+ "licenseId": "SNIA",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/SNIA_Public_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/W3C.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/W3C.json",
+ "referenceNumber": 335,
+ "name": "W3C Software Notice and License (2002-12-31)",
+ "licenseId": "W3C",
+ "seeAlso": [
+ "http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231.html",
+ "https://opensource.org/licenses/W3C"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.3-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.3-or-later.json",
+ "referenceNumber": 336,
+ "name": "GNU Free Documentation License v1.3 or later",
+ "licenseId": "GFDL-1.3-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/fdl-1.3.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/D-FSL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/D-FSL-1.0.json",
+ "referenceNumber": 337,
+ "name": "Deutsche Freie Software Lizenz",
+ "licenseId": "D-FSL-1.0",
+ "seeAlso": [
+ "http://www.dipp.nrw.de/d-fsl/lizenzen/",
+ "http://www.dipp.nrw.de/d-fsl/index_html/lizenzen/de/D-FSL-1_0_de.txt",
+ "http://www.dipp.nrw.de/d-fsl/index_html/lizenzen/en/D-FSL-1_0_en.txt",
+ "https://www.hbz-nrw.de/produkte/open-access/lizenzen/dfsl",
+ "https://www.hbz-nrw.de/produkte/open-access/lizenzen/dfsl/deutsche-freie-software-lizenz",
+ "https://www.hbz-nrw.de/produkte/open-access/lizenzen/dfsl/german-free-software-license",
+ "https://www.hbz-nrw.de/produkte/open-access/lizenzen/dfsl/D-FSL-1_0_de.txt/at_download/file",
+ "https://www.hbz-nrw.de/produkte/open-access/lizenzen/dfsl/D-FSL-1_0_en.txt/at_download/file"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-4.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-4.0.json",
+ "referenceNumber": 338,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 4.0 International",
+ "licenseId": "CC-BY-NC-SA-4.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Naumen.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Naumen.json",
+ "referenceNumber": 339,
+ "name": "Naumen Public License",
+ "licenseId": "Naumen",
+ "seeAlso": [
+ "https://opensource.org/licenses/Naumen"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/FSFAP.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/FSFAP.json",
+ "referenceNumber": 340,
+ "name": "FSF All Permissive License",
+ "licenseId": "FSFAP",
+ "seeAlso": [
+ "https://www.gnu.org/prep/maintain/html_node/License-Notices-for-Other-Files.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-No-Military-License.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-No-Military-License.json",
+ "referenceNumber": 341,
+ "name": "BSD 3-Clause No Military License",
+ "licenseId": "BSD-3-Clause-No-Military-License",
+ "seeAlso": [
+ "https://gitlab.syncad.com/hive/dhive/-/blob/master/LICENSE",
+ "https://github.com/greymass/swift-eosio/blob/master/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-4.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-4.0.json",
+ "referenceNumber": 342,
+ "name": "Creative Commons Attribution Share Alike 4.0 International",
+ "licenseId": "CC-BY-SA-4.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/4.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/xlock.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/xlock.json",
+ "referenceNumber": 343,
+ "name": "xlock License",
+ "licenseId": "xlock",
+ "seeAlso": [
+ "https://fossies.org/linux/tiff/contrib/ras/ras2tif.c"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Sendmail-8.23.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Sendmail-8.23.json",
+ "referenceNumber": 344,
+ "name": "Sendmail License 8.23",
+ "licenseId": "Sendmail-8.23",
+ "seeAlso": [
+ "https://www.proofpoint.com/sites/default/files/sendmail-license.pdf",
+ "https://web.archive.org/web/20181003101040/https://www.proofpoint.com/sites/default/files/sendmail-license.pdf"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MS-PL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MS-PL.json",
+ "referenceNumber": 345,
+ "name": "Microsoft Public License",
+ "licenseId": "MS-PL",
+ "seeAlso": [
+ "http://www.microsoft.com/opensource/licenses.mspx",
+ "https://opensource.org/licenses/MS-PL"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NIST-PD.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NIST-PD.json",
+ "referenceNumber": 346,
+ "name": "NIST Public Domain Notice",
+ "licenseId": "NIST-PD",
+ "seeAlso": [
+ "https://github.com/tcheneau/simpleRPL/blob/e645e69e38dd4e3ccfeceb2db8cba05b7c2e0cd3/LICENSE.txt",
+ "https://github.com/tcheneau/Routing/blob/f09f46fcfe636107f22f2c98348188a65a135d98/README.md"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Community-Spec-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Community-Spec-1.0.json",
+ "referenceNumber": 347,
+ "name": "Community Specification License 1.0",
+ "licenseId": "Community-Spec-1.0",
+ "seeAlso": [
+ "https://github.com/CommunitySpecification/1.0/blob/master/1._Community_Specification_License-v1.md"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CERN-OHL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CERN-OHL-1.1.json",
+ "referenceNumber": 348,
+ "name": "CERN Open Hardware Licence v1.1",
+ "licenseId": "CERN-OHL-1.1",
+ "seeAlso": [
+ "https://www.ohwr.org/project/licenses/wikis/cern-ohl-v1.1"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.2-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.2-or-later.json",
+ "referenceNumber": 349,
+ "name": "GNU Free Documentation License v1.2 or later",
+ "licenseId": "GFDL-1.2-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.2.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-2.0-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-2.0-or-later.json",
+ "referenceNumber": 350,
+ "name": "GNU Library General Public License v2 or later",
+ "licenseId": "LGPL-2.0-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/lgpl-2.0-standalone.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Condor-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Condor-1.1.json",
+ "referenceNumber": 351,
+ "name": "Condor Public License v1.1",
+ "licenseId": "Condor-1.1",
+ "seeAlso": [
+ "http://research.cs.wisc.edu/condor/license.html#condor",
+ "http://web.archive.org/web/20111123062036/http://research.cs.wisc.edu/condor/license.html#condor"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CDDL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CDDL-1.1.json",
+ "referenceNumber": 352,
+ "name": "Common Development and Distribution License 1.1",
+ "licenseId": "CDDL-1.1",
+ "seeAlso": [
+ "http://glassfish.java.net/public/CDDL+GPL_1_1.html",
+ "https://javaee.github.io/glassfish/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Glide.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Glide.json",
+ "referenceNumber": 353,
+ "name": "3dfx Glide License",
+ "licenseId": "Glide",
+ "seeAlso": [
+ "http://www.users.on.net/~triforce/glidexp/COPYING.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OFL-1.0-no-RFN.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OFL-1.0-no-RFN.json",
+ "referenceNumber": 354,
+ "name": "SIL Open Font License 1.0 with no Reserved Font Name",
+ "licenseId": "OFL-1.0-no-RFN",
+ "seeAlso": [
+ "http://scripts.sil.org/cms/scripts/page.php?item_id\u003dOFL10_web"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CMU-Mach.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CMU-Mach.json",
+ "referenceNumber": 355,
+ "name": "CMU Mach License",
+ "licenseId": "CMU-Mach",
+ "seeAlso": [
+ "https://www.cs.cmu.edu/~410/licenses.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ODbL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ODbL-1.0.json",
+ "referenceNumber": 356,
+ "name": "Open Data Commons Open Database License v1.0",
+ "licenseId": "ODbL-1.0",
+ "seeAlso": [
+ "http://www.opendatacommons.org/licenses/odbl/1.0/",
+ "https://opendatacommons.org/licenses/odbl/1-0/"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LOOP.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LOOP.json",
+ "referenceNumber": 357,
+ "name": "Common Lisp LOOP License",
+ "licenseId": "LOOP",
+ "seeAlso": [
+ "https://gitlab.com/embeddable-common-lisp/ecl/-/blob/develop/src/lsp/loop.lsp",
+ "http://git.savannah.gnu.org/cgit/gcl.git/tree/gcl/lsp/gcl_loop.lsp?h\u003dVersion_2_6_13pre",
+ "https://sourceforge.net/p/sbcl/sbcl/ci/master/tree/src/code/loop.lisp",
+ "https://github.com/cl-adams/adams/blob/master/LICENSE.md",
+ "https://github.com/blakemcbride/eclipse-lisp/blob/master/lisp/loop.lisp",
+ "https://gitlab.common-lisp.net/cmucl/cmucl/-/blob/master/src/code/loop.lisp"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Motosoto.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Motosoto.json",
+ "referenceNumber": 358,
+ "name": "Motosoto License",
+ "licenseId": "Motosoto",
+ "seeAlso": [
+ "https://opensource.org/licenses/Motosoto"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-2.1-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-2.1-only.json",
+ "referenceNumber": 359,
+ "name": "GNU Lesser General Public License v2.1 only",
+ "licenseId": "LGPL-2.1-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html",
+ "https://opensource.org/licenses/LGPL-2.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NASA-1.3.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NASA-1.3.json",
+ "referenceNumber": 360,
+ "name": "NASA Open Source Agreement 1.3",
+ "licenseId": "NASA-1.3",
+ "seeAlso": [
+ "http://ti.arc.nasa.gov/opensource/nosa/",
+ "https://opensource.org/licenses/NASA-1.3"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/EUPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EUPL-1.0.json",
+ "referenceNumber": 361,
+ "name": "European Union Public License 1.0",
+ "licenseId": "EUPL-1.0",
+ "seeAlso": [
+ "http://ec.europa.eu/idabc/en/document/7330.html",
+ "http://ec.europa.eu/idabc/servlets/Doc027f.pdf?id\u003d31096"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/zlib-acknowledgement.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/zlib-acknowledgement.json",
+ "referenceNumber": 362,
+ "name": "zlib/libpng License with Acknowledgement",
+ "licenseId": "zlib-acknowledgement",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/ZlibWithAcknowledgement"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SugarCRM-1.1.3.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SugarCRM-1.1.3.json",
+ "referenceNumber": 363,
+ "name": "SugarCRM Public License v1.1.3",
+ "licenseId": "SugarCRM-1.1.3",
+ "seeAlso": [
+ "http://www.sugarcrm.com/crm/SPL"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Widget-Workshop.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Widget-Workshop.json",
+ "referenceNumber": 364,
+ "name": "Widget Workshop License",
+ "licenseId": "Widget-Workshop",
+ "seeAlso": [
+ "https://github.com/novnc/noVNC/blob/master/core/crypto/des.js#L24"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-2-Clause-NetBSD.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/BSD-2-Clause-NetBSD.json",
+ "referenceNumber": 365,
+ "name": "BSD 2-Clause NetBSD License",
+ "licenseId": "BSD-2-Clause-NetBSD",
+ "seeAlso": [
+ "http://www.netbsd.org/about/redistribution.html#default"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Info-ZIP.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Info-ZIP.json",
+ "referenceNumber": 366,
+ "name": "Info-ZIP License",
+ "licenseId": "Info-ZIP",
+ "seeAlso": [
+ "http://www.info-zip.org/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-Advertising-Acknowledgement.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-Advertising-Acknowledgement.json",
+ "referenceNumber": 367,
+ "name": "BSD Advertising Acknowledgement License",
+ "licenseId": "BSD-Advertising-Acknowledgement",
+ "seeAlso": [
+ "https://github.com/python-excel/xlrd/blob/master/LICENSE#L33"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-ND-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-ND-1.0.json",
+ "referenceNumber": 368,
+ "name": "Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic",
+ "licenseId": "CC-BY-NC-ND-1.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nd-nc/1.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-0.json",
+ "referenceNumber": 369,
+ "name": "MIT No Attribution",
+ "licenseId": "MIT-0",
+ "seeAlso": [
+ "https://github.com/aws/mit-0",
+ "https://romanrm.net/mit-zero",
+ "https://github.com/awsdocs/aws-cloud9-user-guide/blob/master/LICENSE-SAMPLECODE"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OCLC-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OCLC-2.0.json",
+ "referenceNumber": 370,
+ "name": "OCLC Research Public License 2.0",
+ "licenseId": "OCLC-2.0",
+ "seeAlso": [
+ "http://www.oclc.org/research/activities/software/license/v2final.htm",
+ "https://opensource.org/licenses/OCLC-2.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OSL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OSL-1.0.json",
+ "referenceNumber": 371,
+ "name": "Open Software License 1.0",
+ "licenseId": "OSL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/OSL-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Saxpath.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Saxpath.json",
+ "referenceNumber": 372,
+ "name": "Saxpath License",
+ "licenseId": "Saxpath",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Saxpath_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/IJG-short.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/IJG-short.json",
+ "referenceNumber": 373,
+ "name": "Independent JPEG Group License - short",
+ "licenseId": "IJG-short",
+ "seeAlso": [
+ "https://sourceforge.net/p/xmedcon/code/ci/master/tree/libs/ljpg/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Zend-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Zend-2.0.json",
+ "referenceNumber": 374,
+ "name": "Zend License v2.0",
+ "licenseId": "Zend-2.0",
+ "seeAlso": [
+ "https://web.archive.org/web/20130517195954/http://www.zend.com/license/2_00.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Cornell-Lossless-JPEG.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Cornell-Lossless-JPEG.json",
+ "referenceNumber": 375,
+ "name": "Cornell Lossless JPEG License",
+ "licenseId": "Cornell-Lossless-JPEG",
+ "seeAlso": [
+ "https://android.googlesource.com/platform/external/dng_sdk/+/refs/heads/master/source/dng_lossless_jpeg.cpp#16",
+ "https://www.mssl.ucl.ac.uk/~mcrw/src/20050920/proto.h",
+ "https://gitlab.freedesktop.org/libopenraw/libopenraw/blob/master/lib/ljpegdecompressor.cpp#L32"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CECILL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CECILL-1.0.json",
+ "referenceNumber": 376,
+ "name": "CeCILL Free Software License Agreement v1.0",
+ "licenseId": "CECILL-1.0",
+ "seeAlso": [
+ "http://www.cecill.info/licences/Licence_CeCILL_V1-fr.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OpenPBS-2.3.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OpenPBS-2.3.json",
+ "referenceNumber": 377,
+ "name": "OpenPBS v2.3 Software License",
+ "licenseId": "OpenPBS-2.3",
+ "seeAlso": [
+ "https://github.com/adaptivecomputing/torque/blob/master/PBS_License.txt",
+ "https://www.mcs.anl.gov/research/projects/openpbs/PBS_License.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-2.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-2.5.json",
+ "referenceNumber": 378,
+ "name": "Creative Commons Attribution Share Alike 2.5 Generic",
+ "licenseId": "CC-BY-SA-2.5",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/2.5/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/DSDP.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/DSDP.json",
+ "referenceNumber": 379,
+ "name": "DSDP License",
+ "licenseId": "DSDP",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/DSDP"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Martin-Birgmeier.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Martin-Birgmeier.json",
+ "referenceNumber": 380,
+ "name": "Martin Birgmeier License",
+ "licenseId": "Martin-Birgmeier",
+ "seeAlso": [
+ "https://github.com/Perl/perl5/blob/blead/util.c#L6136"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CPOL-1.02.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CPOL-1.02.json",
+ "referenceNumber": 381,
+ "name": "Code Project Open License 1.02",
+ "licenseId": "CPOL-1.02",
+ "seeAlso": [
+ "http://www.codeproject.com/info/cpol10.aspx"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-advertising.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-advertising.json",
+ "referenceNumber": 382,
+ "name": "Enlightenment License (e16)",
+ "licenseId": "MIT-advertising",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/MIT_With_Advertising"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/IPA.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/IPA.json",
+ "referenceNumber": 383,
+ "name": "IPA Font License",
+ "licenseId": "IPA",
+ "seeAlso": [
+ "https://opensource.org/licenses/IPA"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-ND-3.0-DE.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-ND-3.0-DE.json",
+ "referenceNumber": 384,
+ "name": "Creative Commons Attribution Non Commercial No Derivatives 3.0 Germany",
+ "licenseId": "CC-BY-NC-ND-3.0-DE",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-nd/3.0/de/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-SA-3.0-DE.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-SA-3.0-DE.json",
+ "referenceNumber": 385,
+ "name": "Creative Commons Attribution Share Alike 3.0 Germany",
+ "licenseId": "CC-BY-SA-3.0-DE",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-sa/3.0/de/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/AMDPLPA.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AMDPLPA.json",
+ "referenceNumber": 386,
+ "name": "AMD\u0027s plpa_map.c License",
+ "licenseId": "AMDPLPA",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/AMD_plpa_map_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SimPL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SimPL-2.0.json",
+ "referenceNumber": 387,
+ "name": "Simple Public License 2.0",
+ "licenseId": "SimPL-2.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/SimPL-2.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/EPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EPL-1.0.json",
+ "referenceNumber": 388,
+ "name": "Eclipse Public License 1.0",
+ "licenseId": "EPL-1.0",
+ "seeAlso": [
+ "http://www.eclipse.org/legal/epl-v10.html",
+ "https://opensource.org/licenses/EPL-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/AGPL-1.0-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AGPL-1.0-only.json",
+ "referenceNumber": 389,
+ "name": "Affero General Public License v1.0 only",
+ "licenseId": "AGPL-1.0-only",
+ "seeAlso": [
+ "http://www.affero.org/oagpl.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SAX-PD.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SAX-PD.json",
+ "referenceNumber": 390,
+ "name": "Sax Public Domain Notice",
+ "licenseId": "SAX-PD",
+ "seeAlso": [
+ "http://www.saxproject.org/copying.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.1-no-invariants-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.1-no-invariants-or-later.json",
+ "referenceNumber": 391,
+ "name": "GNU Free Documentation License v1.1 or later - no invariants",
+ "licenseId": "GFDL-1.1-no-invariants-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.1.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/bzip2-1.0.6.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/bzip2-1.0.6.json",
+ "referenceNumber": 392,
+ "name": "bzip2 and libbzip2 License v1.0.6",
+ "licenseId": "bzip2-1.0.6",
+ "seeAlso": [
+ "https://sourceware.org/git/?p\u003dbzip2.git;a\u003dblob;f\u003dLICENSE;hb\u003dbzip2-1.0.6",
+ "http://bzip.org/1.0.5/bzip2-manual-1.0.5.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/FSFUL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/FSFUL.json",
+ "referenceNumber": 393,
+ "name": "FSF Unlimited License",
+ "licenseId": "FSFUL",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/FSF_Unlimited_License"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Spencer-94.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Spencer-94.json",
+ "referenceNumber": 394,
+ "name": "Spencer License 94",
+ "licenseId": "Spencer-94",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Henry_Spencer_Reg-Ex_Library_License",
+ "https://metacpan.org/release/KNOK/File-MMagic-1.30/source/COPYING#L28"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CFITSIO.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CFITSIO.json",
+ "referenceNumber": 395,
+ "name": "CFITSIO License",
+ "licenseId": "CFITSIO",
+ "seeAlso": [
+ "https://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/f_user/node9.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/AdaCore-doc.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AdaCore-doc.json",
+ "referenceNumber": 396,
+ "name": "AdaCore Doc License",
+ "licenseId": "AdaCore-doc",
+ "seeAlso": [
+ "https://github.com/AdaCore/xmlada/blob/master/docs/index.rst",
+ "https://github.com/AdaCore/gnatcoll-core/blob/master/docs/index.rst",
+ "https://github.com/AdaCore/gnatcoll-db/blob/master/docs/index.rst"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-Source-Code.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-Source-Code.json",
+ "referenceNumber": 397,
+ "name": "BSD Source Code Attribution",
+ "licenseId": "BSD-Source-Code",
+ "seeAlso": [
+ "https://github.com/robbiehanson/CocoaHTTPServer/blob/master/LICENSE.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Noweb.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Noweb.json",
+ "referenceNumber": 398,
+ "name": "Noweb License",
+ "licenseId": "Noweb",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Noweb"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SMPPL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SMPPL.json",
+ "referenceNumber": 399,
+ "name": "Secure Messaging Protocol Public License",
+ "licenseId": "SMPPL",
+ "seeAlso": [
+ "https://github.com/dcblake/SMP/blob/master/Documentation/License.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Linux-man-pages-copyleft-var.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Linux-man-pages-copyleft-var.json",
+ "referenceNumber": 400,
+ "name": "Linux man-pages Copyleft Variant",
+ "licenseId": "Linux-man-pages-copyleft-var",
+ "seeAlso": [
+ "https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man2/set_mempolicy.2#n5"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Barr.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Barr.json",
+ "referenceNumber": 401,
+ "name": "Barr License",
+ "licenseId": "Barr",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Barr"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.1.json",
+ "referenceNumber": 402,
+ "name": "Open LDAP Public License v2.1",
+ "licenseId": "OLDAP-2.1",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003db0d176738e96a0d3b9f85cb51e140a86f21be715"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/TTWL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TTWL.json",
+ "referenceNumber": 403,
+ "name": "Text-Tabs+Wrap License",
+ "licenseId": "TTWL",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/TTWL",
+ "https://github.com/ap/Text-Tabs/blob/master/lib.modern/Text/Tabs.pm#L148"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CNRI-Python-GPL-Compatible.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CNRI-Python-GPL-Compatible.json",
+ "referenceNumber": 404,
+ "name": "CNRI Python Open Source GPL Compatible License Agreement",
+ "licenseId": "CNRI-Python-GPL-Compatible",
+ "seeAlso": [
+ "http://www.python.org/download/releases/1.6.1/download_win/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OSL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OSL-2.0.json",
+ "referenceNumber": 405,
+ "name": "Open Software License 2.0",
+ "licenseId": "OSL-2.0",
+ "seeAlso": [
+ "http://web.archive.org/web/20041020171434/http://www.rosenlaw.com/osl2.0.html"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.3-invariants-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.3-invariants-or-later.json",
+ "referenceNumber": 406,
+ "name": "GNU Free Documentation License v1.3 or later - invariants",
+ "licenseId": "GFDL-1.3-invariants-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/fdl-1.3.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/xpp.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/xpp.json",
+ "referenceNumber": 407,
+ "name": "XPP License",
+ "licenseId": "xpp",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/xpp"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/W3C-19980720.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/W3C-19980720.json",
+ "referenceNumber": 408,
+ "name": "W3C Software Notice and License (1998-07-20)",
+ "licenseId": "W3C-19980720",
+ "seeAlso": [
+ "http://www.w3.org/Consortium/Legal/copyright-software-19980720.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Linux-man-pages-1-para.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Linux-man-pages-1-para.json",
+ "referenceNumber": 409,
+ "name": "Linux man-pages - 1 paragraph",
+ "licenseId": "Linux-man-pages-1-para",
+ "seeAlso": [
+ "https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man2/getcpu.2#n4"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/APL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/APL-1.0.json",
+ "referenceNumber": 410,
+ "name": "Adaptive Public License 1.0",
+ "licenseId": "APL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/APL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CPAL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CPAL-1.0.json",
+ "referenceNumber": 411,
+ "name": "Common Public Attribution License 1.0",
+ "licenseId": "CPAL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/CPAL-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/ClArtistic.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ClArtistic.json",
+ "referenceNumber": 412,
+ "name": "Clarified Artistic License",
+ "licenseId": "ClArtistic",
+ "seeAlso": [
+ "http://gianluca.dellavedova.org/2011/01/03/clarified-artistic-license/",
+ "http://www.ncftp.com/ncftp/doc/LICENSE.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NIST-Software.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NIST-Software.json",
+ "referenceNumber": 413,
+ "name": "NIST Software License",
+ "licenseId": "NIST-Software",
+ "seeAlso": [
+ "https://github.com/open-quantum-safe/liboqs/blob/40b01fdbb270f8614fde30e65d30e9da18c02393/src/common/rand/rand_nist.c#L1-L15"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/UCL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/UCL-1.0.json",
+ "referenceNumber": 414,
+ "name": "Upstream Compatibility License v1.0",
+ "licenseId": "UCL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/UCL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OGL-UK-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OGL-UK-3.0.json",
+ "referenceNumber": 415,
+ "name": "Open Government Licence v3.0",
+ "licenseId": "OGL-UK-3.0",
+ "seeAlso": [
+ "http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/TORQUE-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TORQUE-1.1.json",
+ "referenceNumber": 416,
+ "name": "TORQUE v2.5+ Software License v1.1",
+ "licenseId": "TORQUE-1.1",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/TORQUEv1.1"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NOSL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NOSL.json",
+ "referenceNumber": 417,
+ "name": "Netizen Open Source License",
+ "licenseId": "NOSL",
+ "seeAlso": [
+ "http://bits.netizen.com.au/licenses/NOSL/nosl.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LiLiQ-R-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LiLiQ-R-1.1.json",
+ "referenceNumber": 418,
+ "name": "Licence Libre du Québec – Réciprocité version 1.1",
+ "licenseId": "LiLiQ-R-1.1",
+ "seeAlso": [
+ "https://www.forge.gouv.qc.ca/participez/licence-logicielle/licence-libre-du-quebec-liliq-en-francais/licence-libre-du-quebec-reciprocite-liliq-r-v1-1/",
+ "http://opensource.org/licenses/LiLiQ-R-1.1"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OFL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OFL-1.0.json",
+ "referenceNumber": 419,
+ "name": "SIL Open Font License 1.0",
+ "licenseId": "OFL-1.0",
+ "seeAlso": [
+ "http://scripts.sil.org/cms/scripts/page.php?item_id\u003dOFL10_web"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-2.0.json",
+ "referenceNumber": 420,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 2.0 Generic",
+ "licenseId": "CC-BY-NC-SA-2.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/2.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-Wu.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-Wu.json",
+ "referenceNumber": 421,
+ "name": "MIT Tom Wu Variant",
+ "licenseId": "MIT-Wu",
+ "seeAlso": [
+ "https://github.com/chromium/octane/blob/master/crypto.js"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/RHeCos-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/RHeCos-1.1.json",
+ "referenceNumber": 422,
+ "name": "Red Hat eCos Public License v1.1",
+ "licenseId": "RHeCos-1.1",
+ "seeAlso": [
+ "http://ecos.sourceware.org/old-license.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-Festival.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-Festival.json",
+ "referenceNumber": 423,
+ "name": "MIT Festival Variant",
+ "licenseId": "MIT-Festival",
+ "seeAlso": [
+ "https://github.com/festvox/flite/blob/master/COPYING",
+ "https://github.com/festvox/speech_tools/blob/master/COPYING"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/HPND-sell-variant.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/HPND-sell-variant.json",
+ "referenceNumber": 424,
+ "name": "Historical Permission Notice and Disclaimer - sell variant",
+ "licenseId": "HPND-sell-variant",
+ "seeAlso": [
+ "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/sunrpc/auth_gss/gss_generic_token.c?h\u003dv4.19"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-3.0-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GPL-3.0-or-later.json",
+ "referenceNumber": 425,
+ "name": "GNU General Public License v3.0 or later",
+ "licenseId": "GPL-3.0-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/gpl-3.0-standalone.html",
+ "https://opensource.org/licenses/GPL-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/TOSL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TOSL.json",
+ "referenceNumber": 426,
+ "name": "Trusster Open Source License",
+ "licenseId": "TOSL",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/TOSL"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.2-no-invariants-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.2-no-invariants-only.json",
+ "referenceNumber": 427,
+ "name": "GNU Free Documentation License v1.2 only - no invariants",
+ "licenseId": "GFDL-1.2-no-invariants-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.2.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BlueOak-1.0.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BlueOak-1.0.0.json",
+ "referenceNumber": 428,
+ "name": "Blue Oak Model License 1.0.0",
+ "licenseId": "BlueOak-1.0.0",
+ "seeAlso": [
+ "https://blueoakcouncil.org/license/1.0.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LPPL-1.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LPPL-1.2.json",
+ "referenceNumber": 429,
+ "name": "LaTeX Project Public License v1.2",
+ "licenseId": "LPPL-1.2",
+ "seeAlso": [
+ "http://www.latex-project.org/lppl/lppl-1-2.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/iMatix.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/iMatix.json",
+ "referenceNumber": 430,
+ "name": "iMatix Standard Function Library Agreement",
+ "licenseId": "iMatix",
+ "seeAlso": [
+ "http://legacy.imatix.com/html/sfl/sfl4.htm#license"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LZMA-SDK-9.11-to-9.20.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LZMA-SDK-9.11-to-9.20.json",
+ "referenceNumber": 431,
+ "name": "LZMA SDK License (versions 9.11 to 9.20)",
+ "licenseId": "LZMA-SDK-9.11-to-9.20",
+ "seeAlso": [
+ "https://www.7-zip.org/sdk.html",
+ "https://sourceforge.net/projects/sevenzip/files/LZMA%20SDK/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/TPDL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TPDL.json",
+ "referenceNumber": 432,
+ "name": "Time::ParseDate License",
+ "licenseId": "TPDL",
+ "seeAlso": [
+ "https://metacpan.org/pod/Time::ParseDate#LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-3.0.json",
+ "referenceNumber": 433,
+ "name": "Creative Commons Attribution 3.0 Unported",
+ "licenseId": "CC-BY-3.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/3.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Apache-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Apache-1.0.json",
+ "referenceNumber": 434,
+ "name": "Apache License 1.0",
+ "licenseId": "Apache-1.0",
+ "seeAlso": [
+ "http://www.apache.org/licenses/LICENSE-1.0"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.3.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.3.json",
+ "referenceNumber": 435,
+ "name": "GNU Free Documentation License v1.3",
+ "licenseId": "GFDL-1.3",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/fdl-1.3.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Fair.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Fair.json",
+ "referenceNumber": 436,
+ "name": "Fair License",
+ "licenseId": "Fair",
+ "seeAlso": [
+ "http://fairlicense.org/",
+ "https://opensource.org/licenses/Fair"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/EFL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EFL-2.0.json",
+ "referenceNumber": 437,
+ "name": "Eiffel Forum License v2.0",
+ "licenseId": "EFL-2.0",
+ "seeAlso": [
+ "http://www.eiffel-nice.org/license/eiffel-forum-license-2.html",
+ "https://opensource.org/licenses/EFL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0-only.json",
+ "referenceNumber": 438,
+ "name": "GNU General Public License v2.0 only",
+ "licenseId": "GPL-2.0-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html",
+ "https://opensource.org/licenses/GPL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CERN-OHL-P-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CERN-OHL-P-2.0.json",
+ "referenceNumber": 439,
+ "name": "CERN Open Hardware Licence Version 2 - Permissive",
+ "licenseId": "CERN-OHL-P-2.0",
+ "seeAlso": [
+ "https://www.ohwr.org/project/cernohl/wikis/Documents/CERN-OHL-version-2"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Wsuipa.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Wsuipa.json",
+ "referenceNumber": 440,
+ "name": "Wsuipa License",
+ "licenseId": "Wsuipa",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Wsuipa"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SPL-1.0.json",
+ "referenceNumber": 441,
+ "name": "Sun Public License v1.0",
+ "licenseId": "SPL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/SPL-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License-2014.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License-2014.json",
+ "referenceNumber": 442,
+ "name": "BSD 3-Clause No Nuclear License 2014",
+ "licenseId": "BSD-3-Clause-No-Nuclear-License-2014",
+ "seeAlso": [
+ "https://java.net/projects/javaeetutorial/pages/BerkeleyLicense"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MirOS.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MirOS.json",
+ "referenceNumber": 443,
+ "name": "The MirOS Licence",
+ "licenseId": "MirOS",
+ "seeAlso": [
+ "https://opensource.org/licenses/MirOS"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/blessing.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/blessing.json",
+ "referenceNumber": 444,
+ "name": "SQLite Blessing",
+ "licenseId": "blessing",
+ "seeAlso": [
+ "https://www.sqlite.org/src/artifact/e33a4df7e32d742a?ln\u003d4-9",
+ "https://sqlite.org/src/artifact/df5091916dbb40e6"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Jam.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Jam.json",
+ "referenceNumber": 445,
+ "name": "Jam License",
+ "licenseId": "Jam",
+ "seeAlso": [
+ "https://www.boost.org/doc/libs/1_35_0/doc/html/jam.html",
+ "https://web.archive.org/web/20160330173339/https://swarm.workshop.perforce.com/files/guest/perforce_software/jam/src/README"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-3.0-with-GCC-exception.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-3.0-with-GCC-exception.json",
+ "referenceNumber": 446,
+ "name": "GNU General Public License v3.0 w/GCC Runtime Library exception",
+ "licenseId": "GPL-3.0-with-GCC-exception",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/gcc-exception-3.1.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.4.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.4.json",
+ "referenceNumber": 447,
+ "name": "Open LDAP Public License v2.4",
+ "licenseId": "OLDAP-2.4",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003dcd1284c4a91a8a380d904eee68d1583f989ed386"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/ANTLR-PD.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ANTLR-PD.json",
+ "referenceNumber": 448,
+ "name": "ANTLR Software Rights Notice",
+ "licenseId": "ANTLR-PD",
+ "seeAlso": [
+ "http://www.antlr2.org/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LZMA-SDK-9.22.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LZMA-SDK-9.22.json",
+ "referenceNumber": 449,
+ "name": "LZMA SDK License (versions 9.22 and beyond)",
+ "licenseId": "LZMA-SDK-9.22",
+ "seeAlso": [
+ "https://www.7-zip.org/sdk.html",
+ "https://sourceforge.net/projects/sevenzip/files/LZMA%20SDK/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/PHP-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/PHP-3.0.json",
+ "referenceNumber": 450,
+ "name": "PHP License v3.0",
+ "licenseId": "PHP-3.0",
+ "seeAlso": [
+ "http://www.php.net/license/3_0.txt",
+ "https://opensource.org/licenses/PHP-3.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.2.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.2.1.json",
+ "referenceNumber": 451,
+ "name": "Open LDAP Public License v2.2.1",
+ "licenseId": "OLDAP-2.2.1",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003d4bc786f34b50aa301be6f5600f58a980070f481e"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-2.0-DE.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-2.0-DE.json",
+ "referenceNumber": 452,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 2.0 Germany",
+ "licenseId": "CC-BY-NC-SA-2.0-DE",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/2.0/de/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/libpng-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/libpng-2.0.json",
+ "referenceNumber": 453,
+ "name": "PNG Reference Library version 2",
+ "licenseId": "libpng-2.0",
+ "seeAlso": [
+ "http://www.libpng.org/pub/png/src/libpng-LICENSE.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/UCAR.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/UCAR.json",
+ "referenceNumber": 454,
+ "name": "UCAR License",
+ "licenseId": "UCAR",
+ "seeAlso": [
+ "https://github.com/Unidata/UDUNITS-2/blob/master/COPYRIGHT"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/gnuplot.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/gnuplot.json",
+ "referenceNumber": 455,
+ "name": "gnuplot License",
+ "licenseId": "gnuplot",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Gnuplot"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Nunit.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/Nunit.json",
+ "referenceNumber": 456,
+ "name": "Nunit License",
+ "licenseId": "Nunit",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Nunit"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-2.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-2.5.json",
+ "referenceNumber": 457,
+ "name": "Creative Commons Attribution Non Commercial 2.5 Generic",
+ "licenseId": "CC-BY-NC-2.5",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc/2.5/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NRL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NRL.json",
+ "referenceNumber": 458,
+ "name": "NRL License",
+ "licenseId": "NRL",
+ "seeAlso": [
+ "http://web.mit.edu/network/isakmp/nrllicense.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Python-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Python-2.0.json",
+ "referenceNumber": 459,
+ "name": "Python License 2.0",
+ "licenseId": "Python-2.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/Python-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-2.0-UK.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-2.0-UK.json",
+ "referenceNumber": 460,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 2.0 England and Wales",
+ "licenseId": "CC-BY-NC-SA-2.0-UK",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/2.0/uk/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GL2PS.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GL2PS.json",
+ "referenceNumber": 461,
+ "name": "GL2PS License",
+ "licenseId": "GL2PS",
+ "seeAlso": [
+ "http://www.geuz.org/gl2ps/COPYING.GL2PS"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-ND-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-ND-2.0.json",
+ "referenceNumber": 462,
+ "name": "Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic",
+ "licenseId": "CC-BY-NC-ND-2.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-nd/2.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/AFL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AFL-1.1.json",
+ "referenceNumber": 463,
+ "name": "Academic Free License v1.1",
+ "licenseId": "AFL-1.1",
+ "seeAlso": [
+ "http://opensource.linux-mirror.org/licenses/afl-1.1.txt",
+ "http://wayback.archive.org/web/20021004124254/http://www.opensource.org/licenses/academic.php"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-ND-2.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-ND-2.5.json",
+ "referenceNumber": 464,
+ "name": "Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic",
+ "licenseId": "CC-BY-NC-ND-2.5",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-nd/2.5/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-enna.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-enna.json",
+ "referenceNumber": 465,
+ "name": "enna License",
+ "licenseId": "MIT-enna",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/MIT#enna"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-ND-4.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-ND-4.0.json",
+ "referenceNumber": 466,
+ "name": "Creative Commons Attribution Non Commercial No Derivatives 4.0 International",
+ "licenseId": "CC-BY-NC-ND-4.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSL-1.0.json",
+ "referenceNumber": 467,
+ "name": "Boost Software License 1.0",
+ "licenseId": "BSL-1.0",
+ "seeAlso": [
+ "http://www.boost.org/LICENSE_1_0.txt",
+ "https://opensource.org/licenses/BSL-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0-with-GCC-exception.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0-with-GCC-exception.json",
+ "referenceNumber": 468,
+ "name": "GNU General Public License v2.0 w/GCC Runtime Library exception",
+ "licenseId": "GPL-2.0-with-GCC-exception",
+ "seeAlso": [
+ "https://gcc.gnu.org/git/?p\u003dgcc.git;a\u003dblob;f\u003dgcc/libgcc1.c;h\u003d762f5143fc6eed57b6797c82710f3538aa52b40b;hb\u003dcb143a3ce4fb417c68f5fa2691a1b1b1053dfba9#l10"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Linux-man-pages-copyleft.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Linux-man-pages-copyleft.json",
+ "referenceNumber": 469,
+ "name": "Linux man-pages Copyleft",
+ "licenseId": "Linux-man-pages-copyleft",
+ "seeAlso": [
+ "https://www.kernel.org/doc/man-pages/licenses.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-2.0.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-2.0.json",
+ "referenceNumber": 470,
+ "name": "GNU Library General Public License v2 only",
+ "licenseId": "LGPL-2.0",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/lgpl-2.0-standalone.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-4-Clause.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-4-Clause.json",
+ "referenceNumber": 471,
+ "name": "BSD 4-Clause \"Original\" or \"Old\" License",
+ "licenseId": "BSD-4-Clause",
+ "seeAlso": [
+ "http://directory.fsf.org/wiki/License:BSD_4Clause"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/QPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/QPL-1.0.json",
+ "referenceNumber": 472,
+ "name": "Q Public License 1.0",
+ "licenseId": "QPL-1.0",
+ "seeAlso": [
+ "http://doc.qt.nokia.com/3.3/license.html",
+ "https://opensource.org/licenses/QPL-1.0",
+ "https://doc.qt.io/archives/3.3/license.html"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CERN-OHL-1.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CERN-OHL-1.2.json",
+ "referenceNumber": 473,
+ "name": "CERN Open Hardware Licence v1.2",
+ "licenseId": "CERN-OHL-1.2",
+ "seeAlso": [
+ "https://www.ohwr.org/project/licenses/wikis/cern-ohl-v1.2"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/metamail.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/metamail.json",
+ "referenceNumber": 474,
+ "name": "metamail License",
+ "licenseId": "metamail",
+ "seeAlso": [
+ "https://github.com/Dual-Life/mime-base64/blob/master/Base64.xs#L12"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/checkmk.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/checkmk.json",
+ "referenceNumber": 475,
+ "name": "Checkmk License",
+ "licenseId": "checkmk",
+ "seeAlso": [
+ "https://github.com/libcheck/check/blob/master/checkmk/checkmk.in"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NTP-0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NTP-0.json",
+ "referenceNumber": 476,
+ "name": "NTP No Attribution",
+ "licenseId": "NTP-0",
+ "seeAlso": [
+ "https://github.com/tytso/e2fsprogs/blob/master/lib/et/et_name.c"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Imlib2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Imlib2.json",
+ "referenceNumber": 477,
+ "name": "Imlib2 License",
+ "licenseId": "Imlib2",
+ "seeAlso": [
+ "http://trac.enlightenment.org/e/browser/trunk/imlib2/COPYING",
+ "https://git.enlightenment.org/legacy/imlib2.git/tree/COPYING"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-ND-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-ND-3.0.json",
+ "referenceNumber": 478,
+ "name": "Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported",
+ "licenseId": "CC-BY-NC-ND-3.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-nd/3.0/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/APSL-1.2.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/APSL-1.2.json",
+ "referenceNumber": 479,
+ "name": "Apple Public Source License 1.2",
+ "licenseId": "APSL-1.2",
+ "seeAlso": [
+ "http://www.samurajdata.se/opensource/mirror/licenses/apsl.php"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Mup.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Mup.json",
+ "referenceNumber": 480,
+ "name": "Mup License",
+ "licenseId": "Mup",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Mup"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SSH-OpenSSH.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SSH-OpenSSH.json",
+ "referenceNumber": 481,
+ "name": "SSH OpenSSH license",
+ "licenseId": "SSH-OpenSSH",
+ "seeAlso": [
+ "https://github.com/openssh/openssh-portable/blob/1b11ea7c58cd5c59838b5fa574cd456d6047b2d4/LICENCE#L10"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLFL-1.3.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLFL-1.3.json",
+ "referenceNumber": 482,
+ "name": "Open Logistics Foundation License Version 1.3",
+ "licenseId": "OLFL-1.3",
+ "seeAlso": [
+ "https://openlogisticsfoundation.org/licenses/",
+ "https://opensource.org/license/olfl-1-3/"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-3-Clause-Open-MPI.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-3-Clause-Open-MPI.json",
+ "referenceNumber": 483,
+ "name": "BSD 3-Clause Open MPI variant",
+ "licenseId": "BSD-3-Clause-Open-MPI",
+ "seeAlso": [
+ "https://www.open-mpi.org/community/license.php",
+ "http://www.netlib.org/lapack/LICENSE.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-3.0-with-autoconf-exception.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-3.0-with-autoconf-exception.json",
+ "referenceNumber": 484,
+ "name": "GNU General Public License v3.0 w/Autoconf exception",
+ "licenseId": "GPL-3.0-with-autoconf-exception",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/autoconf-exception-3.0.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/EFL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EFL-1.0.json",
+ "referenceNumber": 485,
+ "name": "Eiffel Forum License v1.0",
+ "licenseId": "EFL-1.0",
+ "seeAlso": [
+ "http://www.eiffel-nice.org/license/forum.txt",
+ "https://opensource.org/licenses/EFL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Intel.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Intel.json",
+ "referenceNumber": 486,
+ "name": "Intel Open Source License",
+ "licenseId": "Intel",
+ "seeAlso": [
+ "https://opensource.org/licenses/Intel"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/Beerware.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Beerware.json",
+ "referenceNumber": 487,
+ "name": "Beerware License",
+ "licenseId": "Beerware",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Beerware",
+ "https://people.freebsd.org/~phk/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CPL-1.0.json",
+ "referenceNumber": 488,
+ "name": "Common Public License 1.0",
+ "licenseId": "CPL-1.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/CPL-1.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/TermReadKey.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TermReadKey.json",
+ "referenceNumber": 489,
+ "name": "TermReadKey License",
+ "licenseId": "TermReadKey",
+ "seeAlso": [
+ "https://github.com/jonathanstowe/TermReadKey/blob/master/README#L9-L10"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MulanPSL-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MulanPSL-2.0.json",
+ "referenceNumber": 490,
+ "name": "Mulan Permissive Software License, Version 2",
+ "licenseId": "MulanPSL-2.0",
+ "seeAlso": [
+ "https://license.coscl.org.cn/MulanPSL2/"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CNRI-Jython.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CNRI-Jython.json",
+ "referenceNumber": 491,
+ "name": "CNRI Jython License",
+ "licenseId": "CNRI-Jython",
+ "seeAlso": [
+ "http://www.jython.org/license.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SHL-0.51.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SHL-0.51.json",
+ "referenceNumber": 492,
+ "name": "Solderpad Hardware License, Version 0.51",
+ "licenseId": "SHL-0.51",
+ "seeAlso": [
+ "https://solderpad.org/licenses/SHL-0.51/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CERN-OHL-W-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CERN-OHL-W-2.0.json",
+ "referenceNumber": 493,
+ "name": "CERN Open Hardware Licence Version 2 - Weakly Reciprocal",
+ "licenseId": "CERN-OHL-W-2.0",
+ "seeAlso": [
+ "https://www.ohwr.org/project/cernohl/wikis/Documents/CERN-OHL-version-2"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-2-Clause-Patent.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-2-Clause-Patent.json",
+ "referenceNumber": 494,
+ "name": "BSD-2-Clause Plus Patent License",
+ "licenseId": "BSD-2-Clause-Patent",
+ "seeAlso": [
+ "https://opensource.org/licenses/BSDplusPatent"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/SunPro.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SunPro.json",
+ "referenceNumber": 495,
+ "name": "SunPro License",
+ "licenseId": "SunPro",
+ "seeAlso": [
+ "https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_acosh.c",
+ "https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_lgammal.c"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/TAPR-OHL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/TAPR-OHL-1.0.json",
+ "referenceNumber": 496,
+ "name": "TAPR Open Hardware License v1.0",
+ "licenseId": "TAPR-OHL-1.0",
+ "seeAlso": [
+ "https://www.tapr.org/OHL"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CERN-OHL-S-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CERN-OHL-S-2.0.json",
+ "referenceNumber": 497,
+ "name": "CERN Open Hardware Licence Version 2 - Strongly Reciprocal",
+ "licenseId": "CERN-OHL-S-2.0",
+ "seeAlso": [
+ "https://www.ohwr.org/project/cernohl/wikis/Documents/CERN-OHL-version-2"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/ZPL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/ZPL-1.1.json",
+ "referenceNumber": 498,
+ "name": "Zope Public License 1.1",
+ "licenseId": "ZPL-1.1",
+ "seeAlso": [
+ "http://old.zope.org/Resources/License/ZPL-1.1"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-4.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-4.0.json",
+ "referenceNumber": 499,
+ "name": "Creative Commons Attribution 4.0 International",
+ "licenseId": "CC-BY-4.0",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by/4.0/legalcode"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BitTorrent-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BitTorrent-1.0.json",
+ "referenceNumber": 500,
+ "name": "BitTorrent Open Source License v1.0",
+ "licenseId": "BitTorrent-1.0",
+ "seeAlso": [
+ "http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/licenses/BitTorrent?r1\u003d1.1\u0026r2\u003d1.1.1.1\u0026diff_format\u003ds"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/libselinux-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/libselinux-1.0.json",
+ "referenceNumber": 501,
+ "name": "libselinux public domain notice",
+ "licenseId": "libselinux-1.0",
+ "seeAlso": [
+ "https://github.com/SELinuxProject/selinux/blob/master/libselinux/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/AFL-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/AFL-3.0.json",
+ "referenceNumber": 502,
+ "name": "Academic Free License v3.0",
+ "licenseId": "AFL-3.0",
+ "seeAlso": [
+ "http://www.rosenlaw.com/AFL3.0.htm",
+ "https://opensource.org/licenses/afl-3.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/X11.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/X11.json",
+ "referenceNumber": 503,
+ "name": "X11 License",
+ "licenseId": "X11",
+ "seeAlso": [
+ "http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CC-BY-NC-SA-3.0-DE.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CC-BY-NC-SA-3.0-DE.json",
+ "referenceNumber": 504,
+ "name": "Creative Commons Attribution Non Commercial Share Alike 3.0 Germany",
+ "licenseId": "CC-BY-NC-SA-3.0-DE",
+ "seeAlso": [
+ "https://creativecommons.org/licenses/by-nc-sa/3.0/de/legalcode"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Bitstream-Vera.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Bitstream-Vera.json",
+ "referenceNumber": 505,
+ "name": "Bitstream Vera Font License",
+ "licenseId": "Bitstream-Vera",
+ "seeAlso": [
+ "https://web.archive.org/web/20080207013128/http://www.gnome.org/fonts/",
+ "https://docubrain.com/sites/default/files/licenses/bitstream-vera.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/RSA-MD.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/RSA-MD.json",
+ "referenceNumber": 506,
+ "name": "RSA Message-Digest License",
+ "licenseId": "RSA-MD",
+ "seeAlso": [
+ "http://www.faqs.org/rfcs/rfc1321.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-4.3TAHOE.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-4.3TAHOE.json",
+ "referenceNumber": 507,
+ "name": "BSD 4.3 TAHOE License",
+ "licenseId": "BSD-4.3TAHOE",
+ "seeAlso": [
+ "https://github.com/389ds/389-ds-base/blob/main/ldap/include/sysexits-compat.h#L15",
+ "https://git.savannah.gnu.org/cgit/indent.git/tree/doc/indent.texi?id\u003da74c6b4ee49397cf330b333da1042bffa60ed14f#n1788"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/EPICS.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/EPICS.json",
+ "referenceNumber": 508,
+ "name": "EPICS Open License",
+ "licenseId": "EPICS",
+ "seeAlso": [
+ "https://epics.anl.gov/license/open.php"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GPL-2.0+.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/GPL-2.0+.json",
+ "referenceNumber": 509,
+ "name": "GNU General Public License v2.0 or later",
+ "licenseId": "GPL-2.0+",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html",
+ "https://opensource.org/licenses/GPL-2.0"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OPL-1.0.json",
+ "referenceNumber": 510,
+ "name": "Open Public License v1.0",
+ "licenseId": "OPL-1.0",
+ "seeAlso": [
+ "http://old.koalateam.com/jackaroo/OPL_1_0.TXT",
+ "https://fedoraproject.org/wiki/Licensing/Open_Public_License"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SHL-0.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SHL-0.5.json",
+ "referenceNumber": 511,
+ "name": "Solderpad Hardware License v0.5",
+ "licenseId": "SHL-0.5",
+ "seeAlso": [
+ "https://solderpad.org/licenses/SHL-0.5/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/FSFULLRWD.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/FSFULLRWD.json",
+ "referenceNumber": 512,
+ "name": "FSF Unlimited License (With License Retention and Warranty Disclaimer)",
+ "licenseId": "FSFULLRWD",
+ "seeAlso": [
+ "https://lists.gnu.org/archive/html/autoconf/2012-04/msg00061.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/WTFPL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/WTFPL.json",
+ "referenceNumber": 513,
+ "name": "Do What The F*ck You Want To Public License",
+ "licenseId": "WTFPL",
+ "seeAlso": [
+ "http://www.wtfpl.net/about/",
+ "http://sam.zoy.org/wtfpl/COPYING"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OPUBL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OPUBL-1.0.json",
+ "referenceNumber": 514,
+ "name": "Open Publication License v1.0",
+ "licenseId": "OPUBL-1.0",
+ "seeAlso": [
+ "http://opencontent.org/openpub/",
+ "https://www.debian.org/opl",
+ "https://www.ctan.org/license/opl"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LAL-1.3.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LAL-1.3.json",
+ "referenceNumber": 515,
+ "name": "Licence Art Libre 1.3",
+ "licenseId": "LAL-1.3",
+ "seeAlso": [
+ "https://artlibre.org/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LPPL-1.3a.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LPPL-1.3a.json",
+ "referenceNumber": 516,
+ "name": "LaTeX Project Public License v1.3a",
+ "licenseId": "LPPL-1.3a",
+ "seeAlso": [
+ "http://www.latex-project.org/lppl/lppl-1-3a.txt"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NBPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NBPL-1.0.json",
+ "referenceNumber": 517,
+ "name": "Net Boolean Public License v1",
+ "licenseId": "NBPL-1.0",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003d37b4b3f6cc4bf34e1d3dec61e69914b9819d8894"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OFL-1.1-RFN.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OFL-1.1-RFN.json",
+ "referenceNumber": 518,
+ "name": "SIL Open Font License 1.1 with Reserved Font Name",
+ "licenseId": "OFL-1.1-RFN",
+ "seeAlso": [
+ "http://scripts.sil.org/cms/scripts/page.php?item_id\u003dOFL_web",
+ "https://opensource.org/licenses/OFL-1.1"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.0.json",
+ "referenceNumber": 519,
+ "name": "Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)",
+ "licenseId": "OLDAP-2.0",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003dcbf50f4e1185a21abd4c0a54d3f4341fe28f36ea"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/SGP4.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/SGP4.json",
+ "referenceNumber": 520,
+ "name": "SGP4 Permission Notice",
+ "licenseId": "SGP4",
+ "seeAlso": [
+ "https://celestrak.org/publications/AIAA/2006-6753/faq.php"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.1-invariants-only.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.1-invariants-only.json",
+ "referenceNumber": 521,
+ "name": "GNU Free Documentation License v1.1 only - invariants",
+ "licenseId": "GFDL-1.1-invariants-only",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/fdl-1.1.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/CECILL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CECILL-1.1.json",
+ "referenceNumber": 522,
+ "name": "CeCILL Free Software License Agreement v1.1",
+ "licenseId": "CECILL-1.1",
+ "seeAlso": [
+ "http://www.cecill.info/licences/Licence_CeCILL_V1.1-US.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/GFDL-1.3-no-invariants-or-later.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/GFDL-1.3-no-invariants-or-later.json",
+ "referenceNumber": 523,
+ "name": "GNU Free Documentation License v1.3 or later - no invariants",
+ "licenseId": "GFDL-1.3-no-invariants-or-later",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/fdl-1.3.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Apache-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Apache-1.1.json",
+ "referenceNumber": 524,
+ "name": "Apache License 1.1",
+ "licenseId": "Apache-1.1",
+ "seeAlso": [
+ "http://apache.org/licenses/LICENSE-1.1",
+ "https://opensource.org/licenses/Apache-1.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NLOD-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NLOD-1.0.json",
+ "referenceNumber": 525,
+ "name": "Norwegian Licence for Open Government Data (NLOD) 1.0",
+ "licenseId": "NLOD-1.0",
+ "seeAlso": [
+ "http://data.norge.no/nlod/en/1.0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Vim.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Vim.json",
+ "referenceNumber": 526,
+ "name": "Vim License",
+ "licenseId": "Vim",
+ "seeAlso": [
+ "http://vimdoc.sourceforge.net/htmldoc/uganda.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/PostgreSQL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/PostgreSQL.json",
+ "referenceNumber": 527,
+ "name": "PostgreSQL License",
+ "licenseId": "PostgreSQL",
+ "seeAlso": [
+ "http://www.postgresql.org/about/licence",
+ "https://opensource.org/licenses/PostgreSQL"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/FSFULLR.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/FSFULLR.json",
+ "referenceNumber": 528,
+ "name": "FSF Unlimited License (with License Retention)",
+ "licenseId": "FSFULLR",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/FSF_Unlimited_License#License_Retention_Variant"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/NLPL.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NLPL.json",
+ "referenceNumber": 529,
+ "name": "No Limit Public License",
+ "licenseId": "NLPL",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/NLPL"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Glulxe.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Glulxe.json",
+ "referenceNumber": 530,
+ "name": "Glulxe License",
+ "licenseId": "Glulxe",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Glulxe"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/libutil-David-Nugent.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/libutil-David-Nugent.json",
+ "referenceNumber": 531,
+ "name": "libutil David Nugent License",
+ "licenseId": "libutil-David-Nugent",
+ "seeAlso": [
+ "http://web.mit.edu/freebsd/head/lib/libutil/login_ok.3",
+ "https://cgit.freedesktop.org/libbsd/tree/man/setproctitle.3bsd"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Zed.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Zed.json",
+ "referenceNumber": 532,
+ "name": "Zed License",
+ "licenseId": "Zed",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Zed"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/FreeImage.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/FreeImage.json",
+ "referenceNumber": 533,
+ "name": "FreeImage Public License v1.0",
+ "licenseId": "FreeImage",
+ "seeAlso": [
+ "http://freeimage.sourceforge.net/freeimage-license.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/0BSD.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/0BSD.json",
+ "referenceNumber": 534,
+ "name": "BSD Zero Clause License",
+ "licenseId": "0BSD",
+ "seeAlso": [
+ "http://landley.net/toybox/license.html",
+ "https://opensource.org/licenses/0BSD"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CDLA-Sharing-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CDLA-Sharing-1.0.json",
+ "referenceNumber": 535,
+ "name": "Community Data License Agreement Sharing 1.0",
+ "licenseId": "CDLA-Sharing-1.0",
+ "seeAlso": [
+ "https://cdla.io/sharing-1-0"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/APSL-1.1.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/APSL-1.1.json",
+ "referenceNumber": 536,
+ "name": "Apple Public Source License 1.1",
+ "licenseId": "APSL-1.1",
+ "seeAlso": [
+ "http://www.opensource.apple.com/source/IOSerialFamily/IOSerialFamily-7/APPLE_LICENSE"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/JasPer-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/JasPer-2.0.json",
+ "referenceNumber": 537,
+ "name": "JasPer License",
+ "licenseId": "JasPer-2.0",
+ "seeAlso": [
+ "http://www.ece.uvic.ca/~mdadams/jasper/LICENSE"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/HTMLTIDY.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/HTMLTIDY.json",
+ "referenceNumber": 538,
+ "name": "HTML Tidy License",
+ "licenseId": "HTMLTIDY",
+ "seeAlso": [
+ "https://github.com/htacg/tidy-html5/blob/next/README/LICENSE.md"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Newsletr.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Newsletr.json",
+ "referenceNumber": 539,
+ "name": "Newsletr License",
+ "licenseId": "Newsletr",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing/Newsletr"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.8.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.8.json",
+ "referenceNumber": 540,
+ "name": "Open LDAP Public License v2.8",
+ "licenseId": "OLDAP-2.8",
+ "seeAlso": [
+ "http://www.openldap.org/software/release/license.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/LPPL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/LPPL-1.0.json",
+ "referenceNumber": 541,
+ "name": "LaTeX Project Public License v1.0",
+ "licenseId": "LPPL-1.0",
+ "seeAlso": [
+ "http://www.latex-project.org/lppl/lppl-1-0.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/O-UDA-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/O-UDA-1.0.json",
+ "referenceNumber": 542,
+ "name": "Open Use of Data Agreement v1.0",
+ "licenseId": "O-UDA-1.0",
+ "seeAlso": [
+ "https://github.com/microsoft/Open-Use-of-Data-Agreement/blob/v1.0/O-UDA-1.0.md",
+ "https://cdla.dev/open-use-of-data-agreement-v1-0/"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/JSON.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/JSON.json",
+ "referenceNumber": 543,
+ "name": "JSON License",
+ "licenseId": "JSON",
+ "seeAlso": [
+ "http://www.json.org/license.html"
+ ],
+ "isOsiApproved": false,
+ "isFsfLibre": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Unicode-DFS-2016.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Unicode-DFS-2016.json",
+ "referenceNumber": 544,
+ "name": "Unicode License Agreement - Data Files and Software (2016)",
+ "licenseId": "Unicode-DFS-2016",
+ "seeAlso": [
+ "https://www.unicode.org/license.txt",
+ "http://web.archive.org/web/20160823201924/http://www.unicode.org/copyright.html#License",
+ "http://www.unicode.org/copyright.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NICTA-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NICTA-1.0.json",
+ "referenceNumber": 545,
+ "name": "NICTA Public Software License, Version 1.0",
+ "licenseId": "NICTA-1.0",
+ "seeAlso": [
+ "https://opensource.apple.com/source/mDNSResponder/mDNSResponder-320.10/mDNSPosix/nss_ReadMe.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/IEC-Code-Components-EULA.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/IEC-Code-Components-EULA.json",
+ "referenceNumber": 546,
+ "name": "IEC Code Components End-user licence agreement",
+ "licenseId": "IEC-Code-Components-EULA",
+ "seeAlso": [
+ "https://www.iec.ch/webstore/custserv/pdf/CC-EULA.pdf",
+ "https://www.iec.ch/CCv1",
+ "https://www.iec.ch/copyright"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Elastic-2.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Elastic-2.0.json",
+ "referenceNumber": 547,
+ "name": "Elastic License 2.0",
+ "licenseId": "Elastic-2.0",
+ "seeAlso": [
+ "https://www.elastic.co/licensing/elastic-license",
+ "https://github.com/elastic/elasticsearch/blob/master/licenses/ELASTIC-LICENSE-2.0.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/MIT-Modern-Variant.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/MIT-Modern-Variant.json",
+ "referenceNumber": 548,
+ "name": "MIT License Modern Variant",
+ "licenseId": "MIT-Modern-Variant",
+ "seeAlso": [
+ "https://fedoraproject.org/wiki/Licensing:MIT#Modern_Variants",
+ "https://ptolemy.berkeley.edu/copyright.htm",
+ "https://pirlwww.lpl.arizona.edu/resources/guide/software/PerlTk/Tixlic.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/OLDAP-2.5.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/OLDAP-2.5.json",
+ "referenceNumber": 549,
+ "name": "Open LDAP Public License v2.5",
+ "licenseId": "OLDAP-2.5",
+ "seeAlso": [
+ "http://www.openldap.org/devel/gitweb.cgi?p\u003dopenldap.git;a\u003dblob;f\u003dLICENSE;hb\u003d6852b9d90022e8593c98205413380536b1b5a7cf"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Artistic-1.0-Perl.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Artistic-1.0-Perl.json",
+ "referenceNumber": 550,
+ "name": "Artistic License 1.0 (Perl)",
+ "licenseId": "Artistic-1.0-Perl",
+ "seeAlso": [
+ "http://dev.perl.org/licenses/artistic.html"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/CAL-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/CAL-1.0.json",
+ "referenceNumber": 551,
+ "name": "Cryptographic Autonomy License 1.0",
+ "licenseId": "CAL-1.0",
+ "seeAlso": [
+ "http://cryptographicautonomylicense.com/license-text.html",
+ "https://opensource.org/licenses/CAL-1.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/BSD-2-Clause-Views.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/BSD-2-Clause-Views.json",
+ "referenceNumber": 552,
+ "name": "BSD 2-Clause with views sentence",
+ "licenseId": "BSD-2-Clause-Views",
+ "seeAlso": [
+ "http://www.freebsd.org/copyright/freebsd-license.html",
+ "https://people.freebsd.org/~ivoras/wine/patch-wine-nvidia.sh",
+ "https://github.com/protegeproject/protege/blob/master/license.txt"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/Interbase-1.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/Interbase-1.0.json",
+ "referenceNumber": 553,
+ "name": "Interbase Public License v1.0",
+ "licenseId": "Interbase-1.0",
+ "seeAlso": [
+ "https://web.archive.org/web/20060319014854/http://info.borland.com/devsupport/interbase/opensource/IPL.html"
+ ],
+ "isOsiApproved": false
+ },
+ {
+ "reference": "https://spdx.org/licenses/LGPL-2.1.html",
+ "isDeprecatedLicenseId": true,
+ "detailsUrl": "https://spdx.org/licenses/LGPL-2.1.json",
+ "referenceNumber": 554,
+ "name": "GNU Lesser General Public License v2.1 only",
+ "licenseId": "LGPL-2.1",
+ "seeAlso": [
+ "https://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html",
+ "https://opensource.org/licenses/LGPL-2.1"
+ ],
+ "isOsiApproved": true,
+ "isFsfLibre": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/NPOSL-3.0.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/NPOSL-3.0.json",
+ "referenceNumber": 555,
+ "name": "Non-Profit Open Software License 3.0",
+ "licenseId": "NPOSL-3.0",
+ "seeAlso": [
+ "https://opensource.org/licenses/NOSL3.0"
+ ],
+ "isOsiApproved": true
+ },
+ {
+ "reference": "https://spdx.org/licenses/gSOAP-1.3b.html",
+ "isDeprecatedLicenseId": false,
+ "detailsUrl": "https://spdx.org/licenses/gSOAP-1.3b.json",
+ "referenceNumber": 556,
+ "name": "gSOAP Public License v1.3b",
+ "licenseId": "gSOAP-1.3b",
+ "seeAlso": [
+ "http://www.cs.fsu.edu/~engelen/license.html"
+ ],
+ "isOsiApproved": false
+ }
+ ],
+ "releaseDate": "2023-06-18"
+}
\ No newline at end of file
diff --git a/test/factories/custom_metadata_types.rb b/test/factories/custom_metadata_types.rb
index 7a08a51c46..daf205934b 100644
--- a/test/factories/custom_metadata_types.rb
+++ b/test/factories/custom_metadata_types.rb
@@ -3,19 +3,19 @@
title { 'age' }
association :sample_attribute_type, factory: :integer_sample_attribute_type
end
-
+
factory(:age_custom_metadata_attribute_with_description_and_label,class:CustomMetadataAttribute) do
title { 'age' }
association :sample_attribute_type, factory: :integer_sample_attribute_type
description { 'You need to enter age.' }
label { 'Biological age' }
end
-
+
factory(:name_custom_metadata_attribute,class:CustomMetadataAttribute) do
title { 'name' }
association :sample_attribute_type, factory: :string_sample_attribute_type
end
-
+
factory(:datetime_custom_metadata_attribute,class:CustomMetadataAttribute) do
title { 'date' }
association :sample_attribute_type, factory: :datetime_sample_attribute_type
@@ -34,12 +34,12 @@
a.custom_metadata_attributes << cv_attribute
end
end
-
+
factory(:cv_list_custom_metadata_attribute,class:CustomMetadataAttribute) do
title { 'CVList' }
association :sample_attribute_type, factory: :datetime_sample_attribute_type
end
-
+
factory(:simple_investigation_custom_metadata_type,class: CustomMetadataType) do
title { 'simple investigation custom metadata type' }
supported_type { 'Investigation' }
@@ -49,7 +49,7 @@
a.custom_metadata_attributes << FactoryBot.create(:datetime_custom_metadata_attribute)
end
end
-
+
factory(:simple_investigation_custom_metadata_type_with_description_and_label,class: CustomMetadataType) do
title { 'simple investigation custom metadata type' }
supported_type { 'Investigation' }
@@ -59,17 +59,17 @@
a.custom_metadata_attributes << FactoryBot.create(:datetime_custom_metadata_attribute)
end
end
-
+
factory(:simple_study_custom_metadata_type, parent: :simple_investigation_custom_metadata_type) do
title { 'simple study custom metadata type' }
supported_type { 'Study' }
end
-
+
factory(:simple_assay_custom_metadata_type, parent: :simple_investigation_custom_metadata_type) do
title { 'simple study custom metadata type' }
supported_type { 'Assay' }
end
-
+
factory(:study_custom_metadata_type_with_spaces, class: CustomMetadataType) do
title { 'study custom metadata type with spaces' }
supported_type { 'Study' }
@@ -79,7 +79,7 @@
end
end
-
+
factory(:study_custom_metadata_type_with_clashes, class: CustomMetadataType) do
title { 'study custom metadata type with clashes' }
supported_type { 'Study' }
@@ -89,7 +89,7 @@
a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'full name')
end
end
-
+
factory(:study_custom_metadata_type_with_symbols, class: CustomMetadataType) do
title { 'study custom metadata type with symbols' }
supported_type { 'Study' }
@@ -100,7 +100,7 @@
a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'name(name)')
end
end
-
+
factory(:study_custom_metadata_type_for_MIAPPE, class: CustomMetadataType) do
title { 'MIAPPE metadata' }
supported_type { 'Study' }
@@ -157,7 +157,7 @@
factory(:role_name_custom_metadata_type,class:CustomMetadataType) do
title { 'role_name' }
- supported_type { 'Study' }
+ supported_type { 'CustomMetadata' }
after(:build) do |a|
a.custom_metadata_attributes << FactoryBot.create(:first_name_custom_metadata_attribute,required: true)
a.custom_metadata_attributes << FactoryBot.create(:last_name_custom_metadata_attribute, required: true)
@@ -166,7 +166,7 @@
factory(:role_address_custom_metadata_type,class:CustomMetadataType) do
title { 'role_address' }
- supported_type { 'Study' }
+ supported_type { 'CustomMetadata' }
after(:build) do |a|
a.custom_metadata_attributes << FactoryBot.create(:street_custom_metadata_attribute,required: true)
a.custom_metadata_attributes << FactoryBot.create(:city_custom_metadata_attribute, required: true)
@@ -218,9 +218,9 @@
association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type
end
- factory(:child_name_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ factory(:child_name_linked_custom_metadata_attribute_multi_attribute,class:CustomMetadataAttribute) do
title { 'child' }
- association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type
+ association :sample_attribute_type, factory: :custom_metadata_multi_sample_attribute_type
association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type
end
@@ -230,8 +230,129 @@
after(:build) do |a|
a.custom_metadata_attributes << FactoryBot.create(:dad_linked_custom_metadata_attribute,required: true)
a.custom_metadata_attributes << FactoryBot.create(:mom_linked_custom_metadata_attribute,required: true)
- a.custom_metadata_attributes << FactoryBot.create(:child_name_linked_custom_metadata_attribute)
+ a.custom_metadata_attributes << FactoryBot.create(:child_name_linked_custom_metadata_attribute_multi_attribute)
+ end
+ end
+
+
+ # for testing linked custom metadata multi
+
+ # case 1
+ factory(:role_affiliation_name_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ title { 'role_affiliation_name' }
+ association :sample_attribute_type, factory: :string_sample_attribute_type
+ end
+
+
+ factory(:identifier_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ title { 'identifier' }
+ association :sample_attribute_type, factory: :string_sample_attribute_type
+ end
+
+ factory(:scheme_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ title { 'scheme' }
+ association :sample_attribute_type, factory: :string_sample_attribute_type
+ end
+
+
+
+ factory(:role_affiliation_identifiers_linked_custom_metadata_attribute_multi_attribute,class:CustomMetadataAttribute) do
+ title { 'role_affiliation_identifiers' }
+ association :sample_attribute_type, factory: :custom_metadata_multi_sample_attribute_type
+ association :linked_custom_metadata_type, factory: :role_affiliation_identifiers_custom_metadata_type
+ end
+
+ factory(:role_affiliation_identifiers_custom_metadata_type,class:CustomMetadataType) do
+ title { 'role_affiliation_identifiers' }
+ supported_type { 'CustomMetadata' }
+ after(:build) do |a|
+ a.custom_metadata_attributes << FactoryBot.create(:identifier_custom_metadata_attribute, required: true)
+ a.custom_metadata_attributes << FactoryBot.create(:scheme_custom_metadata_attribute, required: true)
+ end
+ end
+
+
+ factory(:role_affiliation_custom_metadata_type,class:CustomMetadataType) do
+ title { 'role_affiliation' }
+ supported_type { 'Study' }
+ after(:build) do |a|
+ a.custom_metadata_attributes << FactoryBot.create(:role_affiliation_name_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << FactoryBot.create(:role_affiliation_identifiers_linked_custom_metadata_attribute_multi_attribute,required:true)
+ end
+ end
+
+
+ # case 2
+
+
+ factory(:study_title_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ title { 'study_title' }
+ association :sample_attribute_type, factory: :string_sample_attribute_type
+ end
+
+ factory(:study_site_name_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ title { 'study_site_name' }
+ association :sample_attribute_type, factory: :string_sample_attribute_type
+ end
+
+ factory(:study_site_location_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ title { 'study_site_location' }
+ association :sample_attribute_type, factory: :string_sample_attribute_type
+ end
+
+ factory(:participant_name_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ title { 'participant_name' }
+ association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type
+ association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type
+ end
+
+
+ factory(:participant_age_custom_metadata_attribute,class:CustomMetadataAttribute) do
+ title { 'participant_age' }
+ association :sample_attribute_type, factory: :string_sample_attribute_type
+ end
+
+ factory(:participants_custom_metadata_type,class:CustomMetadataType) do
+ title { 'participants' }
+ supported_type { 'CustomMetadata' }
+ after(:build) do |a|
+ a.custom_metadata_attributes << FactoryBot.create(:participant_name_custom_metadata_attribute, required: true)
+ a.custom_metadata_attributes << FactoryBot.create(:participant_age_custom_metadata_attribute)
+ end
+ end
+
+
+ factory(:participants_linked_custom_metadata_attribute_multi_attribute,class:CustomMetadataAttribute) do
+ title { 'participants' }
+ association :sample_attribute_type, factory: :custom_metadata_multi_sample_attribute_type
+ association :linked_custom_metadata_type, factory: :participants_custom_metadata_type
+ end
+
+
+ factory(:study_sites_custom_metadata_type,class:CustomMetadataType) do
+ title { 'study_sites' }
+ supported_type { 'CustomMetadata' }
+ after(:build) do |a|
+ a.custom_metadata_attributes << FactoryBot.create(:study_site_name_custom_metadata_attribute, required: true)
+ a.custom_metadata_attributes << FactoryBot.create(:study_site_location_custom_metadata_attribute)
+ a.custom_metadata_attributes << FactoryBot.create(:participants_linked_custom_metadata_attribute_multi_attribute,required:true)
+ end
+ end
+
+ factory(:study_sites_linked_custom_metadata_attribute_multi_attribute,class:CustomMetadataAttribute) do
+ title { 'study_sites' }
+ association :sample_attribute_type, factory: :custom_metadata_multi_sample_attribute_type
+ association :linked_custom_metadata_type, factory: :study_sites_custom_metadata_type
+ end
+
+ factory(:study_custom_metadata_type,class:CustomMetadataType) do
+ title { 'study_model' }
+ supported_type { 'Study' }
+ after(:build) do |a|
+ a.custom_metadata_attributes << FactoryBot.create(:study_title_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << FactoryBot.create(:study_sites_linked_custom_metadata_attribute_multi_attribute)
end
end
end
+
diff --git a/test/factories/sample_attribute_types.rb b/test/factories/sample_attribute_types.rb
index ae9641989e..881b9e4385 100644
--- a/test/factories/sample_attribute_types.rb
+++ b/test/factories/sample_attribute_types.rb
@@ -53,6 +53,11 @@
sequence(:title) { |n| "Linked Custom Metadata attribute type #{n}" }
base_type { Seek::Samples::BaseType::LINKED_CUSTOM_METADATA }
end
+
+ factory(:custom_metadata_multi_sample_attribute_type, class: SampleAttributeType) do
+ sequence(:title) { |n| "Linked Custom Metadata multi attribute type #{n}" }
+ base_type { Seek::Samples::BaseType::LINKED_CUSTOM_METADATA_MULTI }
+ end
factory(:data_file_sample_attribute_type, class: SampleAttributeType) do
sequence(:title) { |n| "Data file attribute type #{n}" }
diff --git a/test/fixtures/files/upload_single_page/00_wrong_format_spreadsheet.ods b/test/fixtures/files/upload_single_page/00_wrong_format_spreadsheet.ods
new file mode 100644
index 0000000000..1fbacaba08
Binary files /dev/null and b/test/fixtures/files/upload_single_page/00_wrong_format_spreadsheet.ods differ
diff --git a/test/fixtures/files/upload_single_page/01_combo_update_sources_spreadsheet.xlsx b/test/fixtures/files/upload_single_page/01_combo_update_sources_spreadsheet.xlsx
new file mode 100644
index 0000000000..026a2c5946
Binary files /dev/null and b/test/fixtures/files/upload_single_page/01_combo_update_sources_spreadsheet.xlsx differ
diff --git a/test/fixtures/files/upload_single_page/02_invalid_workbook.xlsx b/test/fixtures/files/upload_single_page/02_invalid_workbook.xlsx
new file mode 100644
index 0000000000..e05a7d4c6d
Binary files /dev/null and b/test/fixtures/files/upload_single_page/02_invalid_workbook.xlsx differ
diff --git a/test/fixtures/files/upload_single_page/03_combo_update_samples_spreadsheet.xlsx b/test/fixtures/files/upload_single_page/03_combo_update_samples_spreadsheet.xlsx
new file mode 100644
index 0000000000..357e00d721
Binary files /dev/null and b/test/fixtures/files/upload_single_page/03_combo_update_samples_spreadsheet.xlsx differ
diff --git a/test/fixtures/files/upload_single_page/04_combo_update_assay_samples_spreadsheet.xlsx b/test/fixtures/files/upload_single_page/04_combo_update_assay_samples_spreadsheet.xlsx
new file mode 100644
index 0000000000..7d7a6f61db
Binary files /dev/null and b/test/fixtures/files/upload_single_page/04_combo_update_assay_samples_spreadsheet.xlsx differ
diff --git a/test/fixtures/files/workflows/ro-crate-with-uri-license.crate.zip b/test/fixtures/files/workflows/ro-crate-with-uri-license.crate.zip
new file mode 100644
index 0000000000..d1c1d9ca68
Binary files /dev/null and b/test/fixtures/files/workflows/ro-crate-with-uri-license.crate.zip differ
diff --git a/test/functional/admin_controller_test.rb b/test/functional/admin_controller_test.rb
index aa7d784018..93b398b473 100644
--- a/test/functional/admin_controller_test.rb
+++ b/test/functional/admin_controller_test.rb
@@ -345,7 +345,7 @@ def setup
test 'snapshot and doi stats' do
investigation = FactoryBot.create(:investigation, title: 'i1', description: 'not blank',
- policy: FactoryBot.create(:downloadable_public_policy))
+ policy: FactoryBot.create(:downloadable_public_policy), creators: [FactoryBot.create(:person)])
snapshot = investigation.create_snapshot
snapshot.update_column(:doi, '10.5072/testytest')
AssetDoiLog.create(asset_type: 'investigation',
diff --git a/test/functional/assays_controller_test.rb b/test/functional/assays_controller_test.rb
index 41b1d850d1..86b8c10ef0 100644
--- a/test/functional/assays_controller_test.rb
+++ b/test/functional/assays_controller_test.rb
@@ -1921,4 +1921,20 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links
assert_select 'span.updated_last_by a', false, 'Last editor should not be shown if editor user has been deleted'
end
+ test 'should delete empty assay with linked sample type' do
+ person = FactoryBot.create(:person)
+ assay_sample_type = FactoryBot.create :linked_sample_type, contributor: person
+ assay = FactoryBot.create(:assay,
+ policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission,contributor: person, access_type:Policy::EDITING)]),
+ sample_type: assay_sample_type,
+ contributor: person)
+
+ login_as(person)
+
+ assert_difference('SampleType.count', -1) do
+ assert_difference('Assay.count', -1) do
+ delete :destroy, params: { id: assay.id, return_to: '/single_pages/' }
+ end
+ end
+ end
end
diff --git a/test/functional/collections_controller_test.rb b/test/functional/collections_controller_test.rb
index 5ff736a97c..409a587d1d 100644
--- a/test/functional/collections_controller_test.rb
+++ b/test/functional/collections_controller_test.rb
@@ -65,13 +65,14 @@ class CollectionsControllerTest < ActionController::TestCase
test 'should show all item types without error' do
all_types_collection = FactoryBot.create(:collection_with_all_types)
- items = all_types_collection.collection_items
+ items = all_types_collection.items
+ assert items.any?
get :show, params: { id: all_types_collection }
assert_response :success
items.each do |item|
- assert_select '#items-table tr a[href=?]', polymorphic_path(item.asset), "#{item.asset_type} collection item missing"
+ assert_select 'ul.feed li a[href=?]', Seek::Util.routes.polymorphic_path(item.asset)
end
end
diff --git a/test/functional/data_files_controller_test.rb b/test/functional/data_files_controller_test.rb
index 0f3f355d8d..6f3ab1061f 100644
--- a/test/functional/data_files_controller_test.rb
+++ b/test/functional/data_files_controller_test.rb
@@ -2094,7 +2094,7 @@ def test_show_item_attributed_to_jerm_file
get :show, params: { id: df }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
end
test 'should display license for current version' do
@@ -2105,11 +2105,11 @@ def test_show_item_attributed_to_jerm_file
get :show, params: { id: df, version: 1 }
assert_response :success
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
get :show, params: { id: df, version: dfv.version }
assert_response :success
- assert_select '.panel .panel-body a', text: 'CC0 1.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Zero v1.0 Universal'
end
test 'should update license' do
@@ -2123,7 +2123,7 @@ def test_show_item_attributed_to_jerm_file
assert_response :redirect
get :show, params: { id: df }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share-Alike 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share Alike 4.0 International'
assert_equal 'CC-BY-SA-4.0', assigns(:data_file).license
end
@@ -2132,7 +2132,7 @@ def test_show_item_attributed_to_jerm_file
get :edit, params: { id: df }
assert_response :success
- assert_select '#license-select option[selected=?]', 'selected', text: 'Creative Commons Attribution Share-Alike 4.0'
+ assert_select '#license-select option[selected=?]', 'selected', text: 'Creative Commons Attribution Share Alike 4.0 International'
df2 = FactoryBot.create :data_file, license: nil, policy: FactoryBot.create(:public_policy)
@@ -2142,7 +2142,7 @@ def test_show_item_attributed_to_jerm_file
register_content_blob
assert_response :success
- assert_select '#license-select option[selected=?]', 'selected', text: 'Creative Commons Attribution 4.0'
+ assert_select '#license-select option[selected=?]', 'selected', text: 'Creative Commons Attribution 4.0 International'
end
test 'can disambiguate sample type' do
diff --git a/test/functional/events_controller_test.rb b/test/functional/events_controller_test.rb
index 98ed264d0d..20c4b12e62 100644
--- a/test/functional/events_controller_test.rb
+++ b/test/functional/events_controller_test.rb
@@ -51,8 +51,10 @@ def test_title
project_ids: [FactoryBot.create(:project, title: 'Dont Display Project').id],
policy: FactoryBot.create(:public_policy)
get :index
- assert !(/Dont Display Person/ =~ @response.body)
- assert !(/Dont Display Project/ =~ @response.body)
+
+ assert_select '.list_items_container .list_item'
+ assert_select '.list_items_container .list_item', text:/Don't Display Person/, count:0
+ assert_select '.list_items_container .list_item', text:/Don't Display Project/, count:0
end
test "shouldn't show hidden items in index" do
diff --git a/test/functional/homes_controller_test.rb b/test/functional/homes_controller_test.rb
index 86a70b155b..51a9d86bc2 100644
--- a/test/functional/homes_controller_test.rb
+++ b/test/functional/homes_controller_test.rb
@@ -259,8 +259,10 @@ class HomesControllerTest < ActionController::TestCase
test 'recently added and download should include snapshot' do
person = FactoryBot.create(:person)
- snapshot1 = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), title: 'inv with snap', contributor: person).create_snapshot
- snapshot2 = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy), title: 'assay with snap', contributor: person).create_snapshot
+ snapshot1 = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ title: 'inv with snap', contributor: person, creators: [person]).create_snapshot
+ snapshot2 = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy),
+ title: 'assay with snap', contributor: person, creators: [person]).create_snapshot
assert_difference 'ActivityLog.count', 2 do
FactoryBot.create(:activity_log, action: 'create', activity_loggable: snapshot1, created_at: 1.day.ago, culprit: person.user)
FactoryBot.create(:activity_log, action: 'download', activity_loggable: snapshot2, created_at: 1.day.ago, culprit: person.user)
@@ -374,7 +376,8 @@ class HomesControllerTest < ActionController::TestCase
df = FactoryBot.create :data_file, title: 'A new data file', contributor: person, policy: FactoryBot.create(:public_policy)
sop = FactoryBot.create :sop, title: 'A new sop', contributor: person, policy: FactoryBot.create(:public_policy)
- assay = FactoryBot.create :assay, title: 'A new assay', contributor: person, policy: FactoryBot.create(:public_policy)
+ assay = FactoryBot.create :assay, title: 'A new assay', contributor: person,
+ policy: FactoryBot.create(:public_policy), creators: [person]
snapshot = assay.create_snapshot
FactoryBot.create :activity_log, activity_loggable: df, controller_name: 'data_files', culprit: person.user
diff --git a/test/functional/investigations_controller_test.rb b/test/functional/investigations_controller_test.rb
index 1e162bf99e..d894635994 100644
--- a/test/functional/investigations_controller_test.rb
+++ b/test/functional/investigations_controller_test.rb
@@ -453,7 +453,7 @@ def test_title
test 'shows how to get a citation for a snapshotted investigation' do
study = FactoryBot.create(:study)
investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
- studies: [study], contributor:study.contributor)
+ studies: [study], contributor:study.contributor, creators: [study.contributor])
login_as(investigation.contributor)
investigation.create_snapshot
@@ -473,7 +473,8 @@ def test_title
another_person = FactoryBot.create(:person,project:person.projects.first)
study = FactoryBot.create(:study,contributor:another_person)
investigation = FactoryBot.create(:investigation, projects:another_person.projects, contributor:another_person,
- policy: FactoryBot.create(:publicly_viewable_policy), studies: [study])
+ policy: FactoryBot.create(:publicly_viewable_policy), studies: [study],
+ creators: [another_person])
login_as(person)
investigation.create_snapshot
diff --git a/test/functional/models_controller_test.rb b/test/functional/models_controller_test.rb
index d9dfac8a73..49a122ecfe 100644
--- a/test/functional/models_controller_test.rb
+++ b/test/functional/models_controller_test.rb
@@ -1040,7 +1040,7 @@ def test_update_should_not_overwrite_contributor
get :show, params: { id: model }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
end
test 'should display license for current version' do
@@ -1051,11 +1051,11 @@ def test_update_should_not_overwrite_contributor
get :show, params: { id: model, version: 1 }
assert_response :success
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
get :show, params: { id: model, version: modelv.version }
assert_response :success
- assert_select '.panel .panel-body a', text: 'CC0 1.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Zero v1.0 Universal'
end
test 'should update license' do
@@ -1070,7 +1070,7 @@ def test_update_should_not_overwrite_contributor
assert_response :redirect
get :show, params: { id: model }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share-Alike 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share Alike 4.0 International'
assert_equal 'CC-BY-SA-4.0', assigns(:model).license
end
diff --git a/test/functional/presentations_controller_test.rb b/test/functional/presentations_controller_test.rb
index 071fe16201..6f8abaf093 100644
--- a/test/functional/presentations_controller_test.rb
+++ b/test/functional/presentations_controller_test.rb
@@ -315,7 +315,7 @@ def setup
get :show, params: { id: presentation }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
end
test 'should display license for current version' do
@@ -326,11 +326,11 @@ def setup
get :show, params: { id: presentation, version: 1 }
assert_response :success
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
get :show, params: { id: presentation, version: presentationv.version }
assert_response :success
- assert_select '.panel .panel-body a', text: 'CC0 1.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Zero v1.0 Universal'
end
test 'should update license' do
@@ -345,7 +345,7 @@ def setup
assert_response :redirect
get :show, params: { id: presentation }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share-Alike 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share Alike 4.0 International'
assert_equal 'CC-BY-SA-4.0', assigns(:presentation).license
end
diff --git a/test/functional/publishing/batch_publishing_test.rb b/test/functional/publishing/batch_publishing_test.rb
index b90cdd2993..6fa1bc2203 100644
--- a/test/functional/publishing/batch_publishing_test.rb
+++ b/test/functional/publishing/batch_publishing_test.rb
@@ -12,10 +12,10 @@ def setup
login_as(@user)
end
- test 'should have the -Publish your assets- only on your own profile' do
+ test 'should have the -Publish your items- only on your own profile' do
get :show, params: { id: User.current_user.person }
assert_response :success
- assert_select 'a[href=?]', batch_publishing_preview_person_path, text: /Publish your assets/
+ assert_select 'a[href=?]', batch_publishing_preview_person_path, text: /Publish your items/
get :batch_publishing_preview, params: { id: User.current_user.person.id }
assert_response :success
@@ -25,7 +25,7 @@ def setup
a_person = FactoryBot.create(:person)
get :show, params: { id: a_person }
assert_response :success
- assert_select 'a', text: /Publish your assets/, count: 0
+ assert_select 'a', text: /Publish your items/, count: 0
get :batch_publishing_preview, params: { id: a_person.id }
assert_redirected_to :root
@@ -44,42 +44,117 @@ def setup
assert a.can_publish?, 'The asset must not be publishable for this test to succeed'
assert a.gatekeeper_required?, "This asset must require gatekeeper's approval for this test to succeed"
end
+
total_asset_count = (publish_immediately_assets + gatekeeper_required_assets).count
get :batch_publishing_preview, params: { id: User.current_user.person.id }
assert_response :success
+ assert_select 'div#sorted_by_type,#sorted_by_isa', count: 2 do |sorted_by|
+ sorted_by.each do |sorted_by_block|
+ assert_select sorted_by_block, '.batch-selection-asset', count: total_asset_count + 1 do # event will also be shown
+ publish_immediately_assets.each do |a|
+ assert_select 'a[href=?]', eval("#{a.class.name.underscore}_path(#{a.id})"), text: /#{a.title}/
+ end
+ gatekeeper_required_assets.each do |a|
+ assert_select 'a[href=?]', eval("#{a.class.name.underscore}_path(#{a.id})"), text: /#{a.title}/
+ end
+ assert_select 'img[src*=?][title=?]', 'lock.png', 'Private', count: total_asset_count
+ end
+
+ assert_select sorted_by_block, '.parent-btn-checkbox', count: total_asset_count + 1 do # event will also be shown
+ publish_immediately_assets.each do |a|
+ assert_select "input[type='checkbox'][id=?]", "publish_#{a.class.name}_#{a.id}"
+ end
+ gatekeeper_required_assets.each do |a|
+ assert_select "input[type='checkbox'][id=?]", "publish_#{a.class.name}_#{a.id}"
+ end
+ end
+ end
+ end
+ end
+
+ test 'Cannot select already-published items in batch_publishing_preview' do
+ published_item = FactoryBot.create(:data_file,
+ contributor: User.current_user.person,
+ policy: FactoryBot.create(:public_policy))
+ assert published_item.is_published?
+
+ get :batch_publishing_preview, params: { id: User.current_user.person.id }
+ assert_response :success
+
+ assert_select '.batch-selection-asset .type_and_title a[href=?]', data_file_path(published_item)
+ assert_select "input[type='checkbox'].#{published_item.class.name}_#{published_item.id}", count: 0
+ end
+
+ test 'publish_final_confirmation' do
+ gatekeeper = FactoryBot.create(:asset_gatekeeper)
+ person = User.current_user.person
+ gatekept_project = gatekeeper.projects.first
+ publishable = FactoryBot.create(:data_file, projects: [person.projects.first], contributor: person)
+ gatekept = FactoryBot.create(:data_file, projects: [gatekept_project], contributor: person)
+ waiting = FactoryBot.create(:data_file, projects: [gatekept_project], contributor: person)
+ ResourcePublishLog.add_log(ResourcePublishLog::WAITING_FOR_APPROVAL, waiting, nil, person.user)
+
+ login_as(person.user)
+ assert publishable.can_publish?
+ assert gatekept.can_publish?
+ assert gatekept.gatekeeper_required?
+ assert !waiting.can_publish?
+
+ params = { publish: {} }
+ [publishable, gatekept, waiting].each do |asset|
+ params[:publish][asset.class.name] ||= {}
+ params[:publish][asset.class.name][asset.id.to_s] = '1'
+ end
+
+ get :check_gatekeeper_required, params: params.merge(id: person.id)
+ assert_response :success
- assert_select '.type_and_title', count: total_asset_count do
- publish_immediately_assets.each do |a|
- assert_select 'a[href=?]', eval("#{a.class.name.underscore}_path(#{a.id})"), text: /#{a.title}/
+ # Publishable shown in immediate publishing section
+ assert_select 'h2', text: /The following items will be published:/, count: 1
+ assert_select 'div.alert-info', text: /immediately accessible to the public/, count: 1
+ assert_select 'ul.publishing_options#publish_immediately', count: 1 do
+ assert_select 'li.type_and_title', count: 1 do
+ assert_select 'a[href=?]', data_file_path(publishable), text: publishable.title
end
- gatekeeper_required_assets.each do |a|
- assert_select 'a[href=?]', eval("#{a.class.name.underscore}_path(#{a.id})"), text: /#{a.title}/
+ end
+ # Gatekept explains waiting approval
+ assert_select 'h2', text: /The following items require approval:/, count: 1
+ assert_select 'div.alert-warning', text: /an email will be sent to that person, and they will either approve or reject/, count: 1
+ assert_select 'ul.publishing_options#waiting_approval', count: 1 do
+ assert_select 'li.type_and_title', count: 1 do
+ assert_select 'a[href=?]', data_file_path(gatekept), text: gatekept.title
end
- assert_select '.type_and_title img[src*=?][title=?]', 'lock.png', 'Private', count: total_asset_count
end
- assert_select '.parent-btn-checkbox', text: /Publish/, count: total_asset_count do
- publish_immediately_assets.each do |a|
- assert_select "input[type='checkbox'][id=?]", "publish_#{a.class.name}_#{a.id}"
- end
- gatekeeper_required_assets.each do |a|
- assert_select "input[type='checkbox'][id=?]", "publish_#{a.class.name}_#{a.id}"
+ # If not-publishable warning is issued
+ assert_select 'h2', text: /The following items cannot be published:/, count: 1
+ assert_select 'div.alert-danger', text: /One or more of the items you selected cannot be published/, count: 1
+ assert_select 'ul.publishing_options#cannot_publish', count: 1 do
+ assert_select 'li.type_and_title', count: 1 do
+ assert_select 'a[href=?]', data_file_path(waiting), text: waiting.title
end
end
end
- test 'do not have not-publishable items in batch_publishing_preview' do
- published_item = FactoryBot.create(:data_file,
- contributor: User.current_user.person,
- policy: FactoryBot.create(:public_policy))
- assert !published_item.can_publish?, 'This data file must not be publishable for the test to succeed'
+ test 'Events are skipped *in publish related items' do
+ person = User.current_user.person
+ assay = FactoryBot.create(:assay, contributor: person)
+ df = FactoryBot.create(:data_file, projects: [person.projects.first], assays: [assay], contributor: person)
+ event = FactoryBot.create(:event, contributor: person)
+ login_as(person.user)
+ assert df.can_publish?
+ assert event.can_publish?
- get :batch_publishing_preview, params: { id: User.current_user.person.id }
+ params = { publish: {} }
+ [df, event].each do |asset|
+ params[:publish][asset.class.name] ||= {}
+ params[:publish][asset.class.name][asset.id.to_s] = '1'
+ end
+
+ get :check_related_items, params: params.merge(id: person.id)
assert_response :success
- assert_select "input[type='checkbox'][id=?]", "publish_#{published_item.class.name}_#{published_item.id}",
- count: 0
end
test 'do not have not_publishable_type item in batch_publishing_preview' do
diff --git a/test/functional/publishing/single_publishing_test.rb b/test/functional/publishing/single_publishing_test.rb
index 8f77468a73..de0ecf3a37 100644
--- a/test/functional/publishing/single_publishing_test.rb
+++ b/test/functional/publishing/single_publishing_test.rb
@@ -109,21 +109,21 @@ def setup
assert_select '.type_and_title', text: /Investigation/, count: 1 do
assert_select 'a[href=?]', investigation_path(investigation), text: /#{investigation.title}/
end
- assert_select '.parent-btn-checkbox', text: /Publish/ do
+ assert_select '.parent-btn-checkbox' do
assert_select "input[type='checkbox'][id=?]", "publish_Investigation_#{investigation.id}"
end
assert_select '.type_and_title', text: /Study/, count: 1 do
assert_select 'a[href=?]', study_path(study), text: /#{study.title}/
end
- assert_select '.parent-btn-checkbox', text: /Publish/ do
+ assert_select '.parent-btn-checkbox' do
assert_select "input[type='checkbox'][id=?]", "publish_Study_#{study.id}"
end
assert_select '.type_and_title', text: /Assay/, count: 1 do
assert_select 'a[href=?]', assay_path(assay), text: /#{assay.title}/
end
- assert_select '.parent-btn-checkbox', text: /Publish/ do
+ assert_select '.parent-btn-checkbox' do
assert_select "input[type='checkbox'][id=?]", "publish_Assay_#{assay.id}"
end
@@ -133,12 +133,12 @@ def setup
assert_select 'a[href=?]', data_file_path(request_publishing_df), text: /#{request_publishing_df.title}/
assert_select 'a[href=?]', data_file_path(notifying_df), text: /#{notifying_df.title}/
end
- assert_select '.parent-btn-checkbox', text: /Publish/ do
+ assert_select '.parent-btn-checkbox' do
assert_select "input[type='checkbox'][id=?]", "publish_DataFile_#{publishing_df.id}"
assert_select "input[type='checkbox'][id=?]", "publish_DataFile_#{request_publishing_df.id}"
end
- assert_select 'span.label-warning', text: "Can't publish", count: 1
+ assert_select '.parent-btn-checkbox.btn-warning[data-tooltip=?]', 'You do not have permission to manage this item.', count: 1
end
test 'split-button recursive selection' do
@@ -162,15 +162,15 @@ def setup
# split-button dropdown menu shown for tree branches
should_have_dropdown.each do |asset|
- assert_select "._#{asset.id}", count: 1 do
+ assert_select '.isa-tree[data-asset-id=?]', "#{asset.class.name}_#{asset.id}", count: 1 do
assert_select '.parent-btn-dropdown', count: 1
assert_select '.dropdown-menu', count: 1 do
assert_select 'li', count: 2 do
- assert_select 'a.selectChildren', text: /Select this item and all of its sub-items./, count: 1 do
+ assert_select 'a.batch-selection-select-children', text: /Select this item and all of its sub-items./, count: 1 do
assert_select 'img[src=?]', '/assets/checkbox_select_all.svg'
end
- assert_select 'a.deselectChildren', text: /Deselect this item and all of its sub-items./, count: 1 do
+ assert_select 'a.batch-selection-deselect-children', text: /Deselect this item and all of its sub-items./, count: 1 do
assert_select 'img[src=?]', '/assets/checkbox_deselect_all.svg'
end
end
@@ -179,7 +179,7 @@ def setup
end
# split-button dropdown menu not shown for tree leafs
should_not_have_dropdown.each do |asset|
- assert_select "._#{asset.id}", count: 1 do
+ assert_select '.isa-tree[data-asset-id=?]', "#{asset.class.name}_#{asset.id}", count: 1 do
assert_select '.parent-btn-dropdown', count: 0
assert_select '.dropdown-menu', count: 0
end
diff --git a/test/functional/sample_types_controller_test.rb b/test/functional/sample_types_controller_test.rb
index 4638ff56f9..825881a6ce 100644
--- a/test/functional/sample_types_controller_test.rb
+++ b/test/functional/sample_types_controller_test.rb
@@ -698,6 +698,22 @@ class SampleTypesControllerTest < ActionController::TestCase
end
end
+ test 'validates changes against editing constraints' do
+ @sample_type.samples.create!(data: { the_title: 'yes' }, sample_type: @sample_type, project_ids: @project_ids)
+
+ assert_no_difference('ActivityLog.count') do
+ put :update, params: { id: @sample_type, sample_type: {
+ sample_attributes_attributes: {
+ '0' => { id: @sample_type.sample_attributes.first.id, pos: '1', title: 'banana', required: '1' }
+ }
+ } }
+ end
+
+ assert_response :unprocessable_entity
+ assert_select 'div#error_explanation' do
+ assert_select 'ul > li', text: 'Sample attributes title cannot be changed (the_title)'
+ end
+ end
private
diff --git a/test/functional/samples_controller_test.rb b/test/functional/samples_controller_test.rb
index 1edaccce44..fe307267e0 100644
--- a/test/functional/samples_controller_test.rb
+++ b/test/functional/samples_controller_test.rb
@@ -233,19 +233,49 @@ class SamplesControllerTest < ActionController::TestCase
get :edit, params: { id: populated_patient_sample.id }
assert_response :success
+ assert_nil flash[:error]
end
- test "can't edit if extracted from a data file" do
+ test "warn on first edit if extracted from a data file" do
person = FactoryBot.create(:person)
sample = FactoryBot.create(:sample_from_file, contributor: person)
login_as(person)
get :edit, params: { id: sample.id }
-
- assert_redirected_to sample_path(sample)
+ assert_response :success
assert_not_nil flash[:error]
end
+ test "source data datafile taged as invalid after edit" do
+ person = FactoryBot.create(:person)
+ sample = FactoryBot.create(:sample_from_file, contributor: person)
+ login_as(person)
+
+ put :update, params: { id: sample.id, sample: { data: { "name": "Modified Sample" } } }
+ sample.reload
+ assert_equal "Modified Sample", sample.title
+ assert sample.edit_count.positive?
+
+ get :show, params: { id: sample.id }
+ assert_response :success
+ assert_select 'span.label-danger', text: /No longer valid/, count: 1
+ end
+
+ test "no longer warn if sample extracted from a data file has already been edited" do
+ person = FactoryBot.create(:person)
+ sample = FactoryBot.create(:sample_from_file, contributor: person)
+ login_as(person)
+
+ put :update, params: { id: sample.id, sample: { data: { "name": "Modified Sample" } } }
+ sample.reload
+ assert_equal "Modified Sample", sample.title
+ assert sample.edit_count.positive?
+
+ get :edit, params: { id: sample.id }
+ assert_response :success
+ assert_nil flash[:error]
+ end
+
#FIXME: there is an inconstency between the existing tests, and how the form behaved - see https://jira-bsse.ethz.ch/browse/OPSK-1205
test 'update from form' do
login_as(FactoryBot.create(:person))
@@ -705,7 +735,7 @@ class SamplesControllerTest < ActionController::TestCase
sample = Sample.create!(sample_type: sample_type, project_ids: person.projects.map(&:id),
data: { title: 'Linking sample',
- patient: linked_sample.id})
+ patient: linked_sample.id })
# For the sample containing the link
get :show, params: { id: sample }
@@ -924,22 +954,30 @@ class SamplesControllerTest < ActionController::TestCase
end
- test 'hide manage menu for manageable but not editable items' do
- # an odd case, where you can manage but not edit, see https://jira-bsse.ethz.ch/browse/OPSK-2041
- person = FactoryBot.create(:person)
- sample = FactoryBot.create(:sample_from_file, contributor:person)
+ test 'manage_update does not invalidate source data' do
+ proj=FactoryBot.create(:project)
+ person = FactoryBot.create(:person, project:proj)
+ other_person = FactoryBot.create(:person)
+ sample = FactoryBot.create(:sample_from_file, contributor: person)
+
login_as(person)
- assert sample.can_manage?
- assert sample.can_view?
- refute sample.can_edit?
+ patch :manage_update, params: { id: sample,
+ sample: { project_ids: [proj.id] },
+ policy_attributes: { access_type: Policy::VISIBLE,
+ permissions_attributes: { '1' => {
+ contributor_type: 'Person',
+ contributor_id: other_person.id,
+ access_type: Policy::MANAGING
+ } } } }
+ assert_redirected_to sample
+ sample.reload
+ assert_equal Policy::VISIBLE, sample.policy.access_type
+ assert_equal 1, sample.policy.permissions.count
+ assert sample.edit_count.zero?
- get :show, params:{ id:sample.id }
+ get :show, params: { id: sample.id }
assert_response :success
-
- assert_select 'a[href=?]',manage_sample_path(sample),text:/manage sample/i, count:0
- assert_select 'a[href=?]',edit_sample_path(sample),text:/edit sample/i, count:0
- assert_select 'a[data-method="delete"][href=?]',sample_path(sample),text:/delete sample/i, count:1
-
+ assert_select 'span.label-danger', text: /No longer valid/, count: 0
end
test 'should create with discussion link' do
@@ -1153,6 +1191,31 @@ class SamplesControllerTest < ActionController::TestCase
end
end
+ test 'create single linked sample' do
+ person = FactoryBot.create(:person)
+ login_as(person)
+ patient = FactoryBot.create(:patient_sample, contributor: person)
+ linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [person.projects.first.id])
+ linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type
+ linked_sample_type.save!
+
+ assert_difference('Sample.count') do
+ post :create, params: { sample: { sample_type_id: linked_sample_type.id,
+ data:{
+ "title": 'Single Sample',
+ "patient": ['', patient.id.to_s]
+ },
+ project_ids: [person.projects.first.id]} }
+ end
+ assert assigns(:sample)
+ sample = assigns(:sample)
+ assert_equal 'Single Sample', sample.title
+
+ assert_equal [patient], sample.linked_samples
+ assert_equal patient.id, sample.get_attribute_value(:patient)['id']
+
+ end
+
test 'create multi linked sample' do
person = FactoryBot.create(:person)
login_as(person)
@@ -1179,11 +1242,37 @@ class SamplesControllerTest < ActionController::TestCase
end
+ test 'validates against linking a private sample' do
+ person = FactoryBot.create(:person)
+ login_as(person)
+ patient = FactoryBot.create(:patient_sample, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:private_policy))
+
+ multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [person.projects.first.id])
+ multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type
+ multi_linked_sample_type.save!
+
+ refute patient.can_view?
+
+ assert_no_difference('Sample.count') do
+ post :create, params: { sample: { sample_type_id: multi_linked_sample_type.id,
+ data:{
+ "title": 'Multiple Samples',
+ "patient": ['',patient.id.to_s]
+ },
+ project_ids: [person.projects.first.id]} }
+ end
+ assert assigns(:sample)
+ refute assigns(:sample).valid?
+
+ end
+
test 'should return max query result' do
with_config_value(:sample_type_template_enabled, true) do
person = FactoryBot.create(:person)
project = FactoryBot.create(:project)
+ login_as(person)
+
template1 = FactoryBot.create(:isa_source_template)
template2 = FactoryBot.create(:isa_sample_collection_template)
template3 = FactoryBot.create(:isa_assay_template)
@@ -1203,7 +1292,7 @@ class SamplesControllerTest < ActionController::TestCase
sample3 = FactoryBot.create :sample, title: 'sample3', sample_type: type3, project_ids: [project.id], contributor: person,
data: { Input: [sample2.id], 'Protocol Assay 1': 'Protocol Assay 1', 'Assay 1 parameter value 1': 'Assay 1 parameter value 1', 'Extract Name': 'Extract Name', 'other material characteristic 1': 'other material characteristic 1' }
- login_as(person)
+
post :query, xhr: true, params: {
project_ids: [project.id],
@@ -1254,6 +1343,99 @@ class SamplesControllerTest < ActionController::TestCase
end
end
+ test 'form hides private linked multi samples' do
+ person = FactoryBot.create(:person)
+ login_as(person)
+
+ patient = FactoryBot.create(:patient_sample, contributor: person, policy: FactoryBot.create(:public_policy))
+ patient.set_attribute_value('full name','Public Patient')
+ patient.save!
+ patient2 = FactoryBot.create(:patient_sample, sample_type:patient.sample_type, contributor: person, policy: FactoryBot.create(:private_policy) )
+ patient2.set_attribute_value('full name','Private Patient')
+ patient2.save!
+ multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [person.projects.first.id])
+ multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type
+ multi_linked_sample_type.save!
+
+ sample = Sample.create(sample_type: multi_linked_sample_type,
+ data:{
+ "title": 'Multiple Samples',
+ "patient": [patient.id.to_s, patient2.id.to_s]
+ },
+ project_ids: [person.projects.first.id],
+ policy: FactoryBot.create(:editing_public_policy)
+ )
+
+ person2 = FactoryBot.create(:person)
+ login_as(person2)
+ assert sample.can_edit?
+
+ get :edit, params: { id: sample.id }
+ assert_response :success
+
+ assert_select 'select#sample_data_patient' do
+ assert_select 'option[value=?]',patient.id, text:/Public Patient/, count:1
+ assert_select 'option[value=?]',patient2.id, text:/Hidden/, count:1
+ assert_select 'option[value=?]',patient2.id, text:/Private Patient/, count:0
+ end
+
+ end
+
+ test 'form hides private linked single sample' do
+ person = FactoryBot.create(:person)
+ login_as(person)
+
+ patient = FactoryBot.create(:patient_sample, contributor: person, policy: FactoryBot.create(:private_policy) )
+ patient.set_attribute_value('full name','Private Patient')
+ patient.save!
+ linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [person.projects.first.id])
+ linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type
+ linked_sample_type.save!
+
+ sample = Sample.create(sample_type: linked_sample_type,
+ data:{
+ "title": 'Single linked sample',
+ "patient": patient.id.to_s
+ },
+ project_ids: [person.projects.first.id],
+ policy: FactoryBot.create(:editing_public_policy)
+ )
+
+ person2 = FactoryBot.create(:person)
+ login_as(person2)
+ assert sample.can_edit?
+
+ get :edit, params: { id: sample.id }
+ assert_response :success
+
+ assert_select 'select#sample_data_patient' do
+ assert_select 'option[value=?]',patient.id, text:/Hidden/, count:1
+ assert_select 'option[value=?]',patient.id, text:/Private Patient/, count:0
+ end
+
+ end
+
+ test 'typeahead' do
+ person = FactoryBot.create(:person)
+ sample1 = FactoryBot.create(:sample, title: 'sample1', contributor: person)
+ sample_type = sample1.sample_type
+
+ sample2 = FactoryBot.create(:sample, sample_type: sample_type, title: 'sample2')
+
+ login_as(person)
+ assert_equal sample1.sample_type, sample2.sample_type
+ assert sample1.can_view?
+ refute sample2.can_view?
+
+ get :typeahead, params:{ format: :json, linked_sample_type_id: sample_type.id, q:'samp'}
+ assert_response :success
+ res = JSON.parse(response.body)['results']
+
+ assert_equal 1, res.count
+ assert_equal 'sample1', res.first['text']
+
+ end
+
private
def populated_patient_sample
diff --git a/test/functional/sharing/batch_sharing_change_test.rb b/test/functional/sharing/batch_sharing_change_test.rb
index a58e0ce1e3..5f56f0439c 100644
--- a/test/functional/sharing/batch_sharing_change_test.rb
+++ b/test/functional/sharing/batch_sharing_change_test.rb
@@ -38,32 +38,59 @@ def setup
login_as(@user)
person = User.current_user.person
- bulk_create_sharing_assets
+ bulk_create_sharing_assets # Creates one of each everything
+ Sop.last.assays = [Assay.last] # Links sop with isa structure
+
+ # Add manageable df link to isa that cannot be managed
+ other_user = FactoryBot.create(:user).person
+ o_inv=FactoryBot.create(:investigation, contributor: other_user)
+ o_study = FactoryBot.create(:study, investigation: o_inv, contributor: other_user)
+ o_assay = FactoryBot.create(:assay, study: o_study, contributor: other_user, policy: FactoryBot.create(:policy, access_type: Policy::VISIBLE))
+ df = FactoryBot.create(:data_file, contributor: @user.person, assay_ids: [o_assay.id])
+ assert df.can_manage?
+ assert !o_assay.can_manage?
+ assert !o_study.can_manage?
+ assert !o_inv.can_manage?
+
+ # Items that can be changed should be 1 of each except events(+1), investigations(+2), studies(+1) and datafiles(+1)
+ related_items_count = Seek::Util.authorized_types.length + 5
get :batch_sharing_permission_preview, params: { id: person.id }
assert_response :success
-
- assert_select 'a[href=?]', "/people/#{person.id}", text:/#{person.name}/, count:1
- assert_select 'div#jstree', count:1
- assert_select 'div#jstree_not_isa', count:1
+ assert_select 'h1', text: /items related to/, count: 1 do
+ assert_select 'a[href=?]', "/people/#{person.id}", text: /#{person.name}/, count: 1
+ end
+ assert_select 'div#sorted_by_type', count: 1 do
+ # Should see all items with policies
+ assert_select '.type_and_title', count: related_items_count
+ assert_select '[type=checkbox]', count: related_items_count
+ end
+ assert_select 'div#sorted_by_isa', count: 1 do
+ # Should see all items with policies and blocked ISA
+ assert_select '.type_and_title', count: related_items_count + 3
+ assert_select '[type=checkbox]', count: related_items_count
+ assert_select '.parent-btn-checkbox.cant_manage', count: 1
+ assert_select '.parent-btn-checkbox.not_visible', count: 2
+ assert_select '.type_and_title', text: /This item is hidden to you/, count: 2 # Doesn't even show title
+ end
end
test 'should list the selected items' do
- params = { share_not_isa: {}, share_isa: {}}
+ params = { publish: {} }
params= params.merge(id: @person.id)
post :batch_change_permission_for_selected_items, params: params
assert_response :redirect
assert_equal flash[:error], 'Please choose at least one item!'
- #selected items don't include downloadable items
- params[:share_not_isa] = {}
+ # selected items don't include downloadable items
+ params[:publish] = {}
event = FactoryBot.create(:event, contributor: @person)
- params[:share_not_isa][event.class.name]||= {}
- params[:share_not_isa][event.class.name][event.id.to_s] = '1'
+ params[:publish][event.class.name] ||= {}
+ params[:publish][event.class.name][event.id.to_s] = '1'
post :batch_change_permission_for_selected_items, params: params.merge(id: @person.id)
assert_select '.highlight-colour', count: 0
@@ -72,22 +99,22 @@ def setup
end
#selected items include downloadable items
- params[:share_not_isa] = {}
+ params[:publish] = {}
model = FactoryBot.create(:model, contributor: @person, projects: [@person.projects.first])
- params[:share_not_isa][model.class.name] ||= {}
- params[:share_not_isa][model.class.name][model.id.to_s] = '1'
+ params[:publish][model.class.name] ||= {}
+ params[:publish][model.class.name][model.id.to_s] = '1'
df = data_with_isa
- params[:share_isa][df.class.name]||= {}
- params[:share_isa][df.class.name][df.id.to_s] = '1'
+ params[:publish][df.class.name] ||= {}
+ params[:publish][df.class.name][df.id.to_s] = '1'
post :batch_change_permission_for_selected_items, params: params.merge(id: @person.id)
assert_select '.type_and_title', count: 2 do
- assert_select 'a[href=?]', data_file_path(df), text:/#{df.title}/
- assert_select 'a[href=?]', model_path(model), text:/#{model.title}/
+ assert_select 'a[href=?]', data_file_path(df), text: /#{df.title}/
+ assert_select 'a[href=?]', model_path(model), text: /#{model.title}/
assert_select '.icon', count: 2
end
- assert_select '.highlight-colour', count: 1, text:/Download/
+ assert_select '.highlight-colour', count: 1, text: /Download/
end
@@ -105,15 +132,15 @@ def setup
assert !df.can_download?(other_person)
- params = { share_not_isa: {}, share_isa: {}}
- params[:share_not_isa][model.class.name] ||= {}
- params[:share_not_isa][model.class.name][model.id.to_s] = '1'
- params[:share_isa][df.class.name]||= {}
- params[:share_isa][df.class.name][df.id.to_s] = '1'
- params[:share_isa]['Banana'] = { '123' => '1' } # Should be ignored
+ params = { publish: {} }
+ params[:publish][model.class.name] ||= {}
+ params[:publish][model.class.name][model.id.to_s] = '1'
+ params[:publish][df.class.name] ||= {}
+ params[:publish][df.class.name][df.id.to_s] = '1'
+ params[:publish]['Banana'] = { '123': '1' } # Should be ignored
# batch change sharing policy and grant other_people manage right
- params[:policy_attributes] = {access_type: Policy::NO_ACCESS, permissions_attributes: {'1' => {contributor_type: 'Person', contributor_id: other_person.id, access_type: Policy::MANAGING}}}
+ params[:policy_attributes] = {access_type: Policy::NO_ACCESS, permissions_attributes: {'1': {contributor_type: 'Person', contributor_id: other_person.id, access_type: Policy::MANAGING}}}
params= params.merge(id: @person.id)
post :batch_sharing_permission_changed, params: params
assert_response :success
@@ -150,13 +177,13 @@ def setup
assert !df.gatekeeper_required?
# Batch change sharing policy params
- params = { share_not_isa: {}, share_isa: {}}
- params[:share_not_isa][gk_model.class.name] ||= {}
- params[:share_not_isa][gk_model.class.name][gk_model.id.to_s] = '1'
- params[:share_isa][gk_df.class.name] ||= {}
- params[:share_isa][gk_df.class.name][gk_df.id.to_s] = '1'
- params[:share_isa][df.class.name] ||= {}
- params[:share_isa][df.class.name][df.id.to_s] = '1'
+ params = { publish: {} }
+ params[:publish][gk_model.class.name] ||= {}
+ params[:publish][gk_model.class.name][gk_model.id.to_s] = '1'
+ params[:publish][gk_df.class.name] ||= {}
+ params[:publish][gk_df.class.name][gk_df.id.to_s] = '1'
+ params[:publish][df.class.name] ||= {}
+ params[:publish][df.class.name][df.id.to_s] = '1'
params = params.merge(id: a_person.id)
# Can't make public without involving gatekeeper
diff --git a/test/functional/single_pages_controller_test.rb b/test/functional/single_pages_controller_test.rb
index d31df57204..9e96bba7a6 100644
--- a/test/functional/single_pages_controller_test.rb
+++ b/test/functional/single_pages_controller_test.rb
@@ -6,7 +6,7 @@ class SinglePagesControllerTest < ActionController::TestCase
fixtures :isa_tags, :templates
def setup
- @instance_name = Seek::Config::instance_name
+ @instance_name = Seek::Config.instance_name
@member = FactoryBot.create :user
login_as @member
end
@@ -22,11 +22,11 @@ def setup
test 'should hide inaccessible items in treeview' do
project = FactoryBot.create(:project)
FactoryBot.create(:investigation, contributor: @member.person, policy: FactoryBot.create(:private_policy),
- projects: [project])
+ projects: [project])
login_as(FactoryBot.create(:user))
inv_two = FactoryBot.create(:investigation, contributor: User.current_user.person, policy: FactoryBot.create(:private_policy),
- projects: [project])
+ projects: [project])
controller = TreeviewBuilder.new project, nil
result = controller.send(:build_tree_data)
@@ -50,38 +50,9 @@ def setup
test 'generates a valid export of sources in single page' do
with_config_value(:project_single_page_enabled, true) do
# Generate the excel data
- person = @member.person
- project = FactoryBot.create(:project)
- study = FactoryBot.create(:study)
- id_label = "#{Seek::Config::instance_name} id"
-
- source_sample_type = FactoryBot.create(:isa_source_sample_type,
- contributor: person,
- project_ids: [project.id],
- isa_template: Template.find_by_title('ISA Source'),
- studies: [study])
-
- sources = (1..5).map do |n|
- FactoryBot.create(
- :sample,
- title: "source#{n}",
- sample_type: source_sample_type,
- project_ids: [project.id],
- contributor: person,
- data: {
- 'Source Name': 'Source Name',
- 'Source Characteristic 1': 'Source Characteristic 1',
- 'Source Characteristic 2':
- source_sample_type
- .sample_attributes
- .find_by_title('Source Characteristic 2')
- .sample_controlled_vocab
- .sample_controlled_vocab_terms
- .first
- .label
- }
- )
- end
+ id_label, person, project, study, source_sample_type, sources = setup_file_upload.values_at(
+ :id_label, :person, :project, :study, :source_sample_type, :sources
+ )
source_ids = sources.map { |s| { id_label => s.id } }
sample_type_id = source_sample_type.id
@@ -108,63 +79,9 @@ def setup
test 'generates a valid export of source samples in single page' do
with_config_value(:project_single_page_enabled, true) do
- person = @member.person
- project = FactoryBot.create(:project)
- study = FactoryBot.create(:study)
- assay = FactoryBot.create(:assay)
- id_label = "#{Seek::Config::instance_name} id"
-
- source_sample_type = FactoryBot.create(:isa_source_sample_type,
- contributor: person,
- project_ids: [project.id],
- isa_template: Template.find_by_title('ISA Source'),
- studies: [study])
-
- sample_collection_sample_type = FactoryBot.create(:isa_sample_collection_sample_type,
- contributor: person,
- project_ids: [project.id],
- isa_template: Template.find_by_title('ISA sample collection'),
- studies: [study],
- linked_sample_type: source_sample_type)
-
- sources = (1..5).map do |n|
- FactoryBot.create(
- :sample,
- title: "source #{n}",
- sample_type: source_sample_type,
- project_ids: [project.id],
- contributor: person,
- data: {
- 'Source Name': 'Source Name',
- 'Source Characteristic 1': 'Source Characteristic 1',
- 'Source Characteristic 2':
- source_sample_type
- .sample_attributes
- .find_by_title('Source Characteristic 2')
- .sample_controlled_vocab
- .sample_controlled_vocab_terms
- .first
- .label
- }
- )
- end
-
- source_samples = (1..4).map do |n|
- FactoryBot.create(
- :sample,
- title: "Sample collection #{n}",
- sample_type: sample_collection_sample_type,
- project_ids: [project.id],
- contributor: person,
- data: {
- Input: [sources[n - 1].id, sources[n].id],
- 'sample collection': 'sample collection',
- 'sample collection parameter value 1': 'sample collection parameter value 1',
- 'Sample Name': 'sample name',
- 'sample characteristic 1': 'sample characteristic 1'
- }
- )
- end
+ id_label, study, assay, sample_collection_sample_type, source_samples = setup_file_upload.values_at(
+ :id_label, :study, :assay, :sample_collection_sample_type, :source_samples
+ )
source_sample_ids = source_samples.map { |ss| { id_label => ss.id } }
sample_type_id = sample_collection_sample_type.id
@@ -181,11 +98,236 @@ def setup
assert_response :ok, msg = "Couldn't reach the server"
response_body = JSON.parse(response.body)
- assert response_body.key?("uuid"), msg = "Response body is expected to have a 'uuid' key"
- cache_uuid = response_body["uuid"]
+ assert response_body.key?('uuid'), msg = "Response body is expected to have a 'uuid' key"
+ cache_uuid = response_body['uuid']
get :download_samples_excel, params: { uuid: cache_uuid }
assert_response :ok, msg = 'Unable to generate the excel'
end
end
+
+ test 'invalid file extension should raise exception' do
+ with_config_value(:project_single_page_enabled, true) do
+ file_path = 'upload_single_page/00_wrong_format_spreadsheet.ods'
+ file = fixture_file_upload(file_path, 'application/vnd.oasis.opendocument.spreadsheet')
+
+ project, source_sample_type = setup_file_upload.values_at(
+ :project, :source_sample_type
+ )
+
+ post :upload_samples, params: { file:, project_id: project.id,
+ sample_type_id: source_sample_type.id }
+
+ assert_response :bad_request
+ assert_equal flash[:error], "Please upload a valid spreadsheet file with extension '.xlsx'"
+ end
+ end
+
+ test 'Should prevent to upload to the wrong Sample Type' do
+ with_config_value(:project_single_page_enabled, true) do
+ project, sample_collection_sample_type = setup_file_upload.values_at(
+ :project, :sample_collection_sample_type
+ )
+
+ file_path = 'upload_single_page/01_combo_update_sources_spreadsheet.xlsx'
+ file = fixture_file_upload(file_path, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
+
+ post :upload_samples, as: :json, params: { file:, project_id: project.id,
+ sample_type_id: sample_collection_sample_type.id }
+
+ assert_response :bad_request
+ end
+ end
+
+ test 'Should not process invalid workbooks' do
+ with_config_value(:project_single_page_enabled, true) do
+ project, source_sample_type = setup_file_upload.values_at(
+ :project, :source_sample_type
+ )
+
+ file_path = 'upload_single_page/02_invalid_workbook.xlsx'
+ file = fixture_file_upload(file_path, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
+
+ post :upload_samples, as: :json, params: { file:, project_id: project.id,
+ sample_type_id: source_sample_type.id }
+
+ assert_response :bad_request
+ end
+ end
+
+ test 'Should update, create and detect duplicate sources when uploading to a source Sample Type' do
+ with_config_value(:project_single_page_enabled, true) do
+ project, source_sample_type = setup_file_upload.values_at(
+ :project, :source_sample_type
+ )
+
+ file_path = 'upload_single_page/01_combo_update_sources_spreadsheet.xlsx'
+ file = fixture_file_upload(file_path, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
+
+ post :upload_samples, as: :json, params: { file:, project_id: project.id,
+ sample_type_id: source_sample_type.id }
+
+ response_data = JSON.parse(response.body)['uploadData']
+ assert_response :success
+
+ updated_samples = response_data['updateSamples']
+ assert(updated_samples.size, 2)
+
+ new_samples = response_data['newSamples']
+ assert(new_samples.size, 2)
+
+ possible_duplicates = response_data['possibleDuplicates']
+ assert(possible_duplicates.size, 1)
+ end
+ end
+
+ test 'Should update, create and detect duplicate samples when uploading to a source sample Sample Type' do
+ with_config_value(:project_single_page_enabled, true) do
+ project, sample_collection_sample_type = setup_file_upload.values_at(
+ :project, :sample_collection_sample_type
+ )
+
+ file_path = 'upload_single_page/03_combo_update_samples_spreadsheet.xlsx'
+ file = fixture_file_upload(file_path, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
+
+ post :upload_samples, as: :json, params: { file:, project_id: project.id,
+ sample_type_id: sample_collection_sample_type.id }
+
+ response_data = JSON.parse(response.body)['uploadData']
+ assert_response :success
+
+ updated_samples = response_data['updateSamples']
+ assert(updated_samples.size, 2)
+
+ new_samples = response_data['newSamples']
+ assert(new_samples.size, 2)
+
+ possible_duplicates = response_data['possibleDuplicates']
+ assert(possible_duplicates.size, 1)
+ end
+ end
+
+ test 'Should update, create and detect duplicate samples when uploading to a assay Sample Type' do
+ with_config_value(:project_single_page_enabled, true) do
+ project, assay_sample_type = setup_file_upload.values_at(
+ :project, :assay_sample_type
+ )
+
+ file_path = 'upload_single_page/04_combo_update_assay_samples_spreadsheet.xlsx'
+ file = fixture_file_upload(file_path, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
+
+ post :upload_samples, as: :json, params: { file:, project_id: project.id,
+ sample_type_id: assay_sample_type.id }
+
+ response_data = JSON.parse(response.body)['uploadData']
+ assert_response :success
+
+ updated_samples = response_data['updateSamples']
+ assert(updated_samples.size, 2)
+
+ new_samples = response_data['newSamples']
+ assert(new_samples.size, 1)
+
+ possible_duplicates = response_data['possibleDuplicates']
+ assert(possible_duplicates.size, 1)
+ end
+ end
+
+ def setup_file_upload
+ id_label = "#{Seek::Config.instance_name} id"
+ person = @member.person
+ project = FactoryBot.create(:project, id: 10_000)
+ study = FactoryBot.create(:study, id: 10_001)
+ assay = FactoryBot.create(:assay, id: 10_002, study:)
+
+ source_sample_type_template = FactoryBot.create(:isa_source_template, id: 10_006)
+ source_sample_type = FactoryBot.create(:isa_source_sample_type,
+ id: 10_003,
+ contributor: person,
+ project_ids: [project.id],
+ isa_template: source_sample_type_template,
+ studies: [study])
+
+ sample_collection_sample_type_template = FactoryBot.create(:isa_sample_collection_template, id: 10_007)
+ sample_collection_sample_type = FactoryBot.create(:isa_sample_collection_sample_type,
+ id: 10_004,
+ contributor: person,
+ project_ids: [project.id],
+ isa_template: sample_collection_sample_type_template,
+ studies: [study],
+ linked_sample_type: source_sample_type)
+
+ assay_sample_type_template = FactoryBot.create(:isa_assay_template, id: 10_008)
+ assay_sample_type = FactoryBot.create(:isa_assay_sample_type,
+ id: 10_005,
+ contributor: person,
+ isa_template: assay_sample_type_template,
+ projects: [project],
+ studies: [study],
+ linked_sample_type: sample_collection_sample_type)
+
+ sources = (1..5).map do |n|
+ FactoryBot.create(
+ :sample,
+ id: 10_010 + n,
+ title: "source#{n}",
+ sample_type: source_sample_type,
+ project_ids: [project.id],
+ contributor: person,
+ data: {
+ 'Source Name': 'Source Name',
+ 'Source Characteristic 1': 'Source Characteristic 1',
+ 'Source Characteristic 2':
+ source_sample_type
+ .sample_attributes
+ .find_by_title('Source Characteristic 2')
+ .sample_controlled_vocab
+ .sample_controlled_vocab_terms
+ .first
+ .label
+ }
+ )
+ end
+
+ source_samples = (1..4).map do |n|
+ FactoryBot.create(
+ :sample,
+ id: 10_020 + n,
+ title: "Sample collection #{n}",
+ sample_type: sample_collection_sample_type,
+ project_ids: [project.id],
+ contributor: person,
+ data: {
+ Input: [sources[n - 1].id, sources[n].id],
+ 'sample collection': 'sample collection',
+ 'sample collection parameter value 1': 'sample collection parameter value 1',
+ 'Sample Name': "sample nr. #{n}",
+ 'sample characteristic 1': 'sample characteristic 1'
+ }
+ )
+ end
+
+ assay_samples = (1..3).map do |n|
+ FactoryBot.create(
+ :sample,
+ id: 10_030 + n,
+ title: "Assay Sample #{n}",
+ sample_type: assay_sample_type,
+ project_ids: [project.id],
+ contributor: person,
+ data: {
+ Input: [source_samples[n - 1].id, source_samples[n].id],
+ 'Protocol Assay 1': 'How to make concentrated dark matter',
+ 'Assay 1 parameter value 1': 'Assay 1 parameter value 1',
+ 'Extract Name': "Extract nr. #{n}",
+ 'other material characteristic 1': 'other material characteristic 1'
+ }
+ )
+ end
+
+ { "id_label": id_label, "person": person, "project": project, "study": study, "assay": assay,
+ "source_sample_type": source_sample_type, "sample_collection_sample_type": sample_collection_sample_type,
+ "assay_sample_type": assay_sample_type, "sources": sources, "source_samples": source_samples,
+ "assay_samples": assay_samples }
+ end
end
diff --git a/test/functional/snapshots_controller_test.rb b/test/functional/snapshots_controller_test.rb
index ef3a5a5e19..000b40a499 100644
--- a/test/functional/snapshots_controller_test.rb
+++ b/test/functional/snapshots_controller_test.rb
@@ -17,7 +17,8 @@ class SnapshotsControllerTest < ActionController::TestCase
test 'can get snapshot preview page' do
user = FactoryBot.create(:user)
- investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person)
+ investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: user.person, creators: [user.person])
login_as(user)
get :new, params: { investigation_id: investigation }
@@ -30,7 +31,8 @@ class SnapshotsControllerTest < ActionController::TestCase
test "can't get snapshot preview if no manage permissions" do
user = FactoryBot.create(:user)
- investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy))
+ investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ creators: [FactoryBot.create(:user).person])
login_as(user)
get :new, params: { investigation_id: investigation }
@@ -42,7 +44,8 @@ class SnapshotsControllerTest < ActionController::TestCase
test "can't get snapshot preview if not publicly accessible" do
user = FactoryBot.create(:user)
- investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy), contributor: user.person)
+ investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy),
+ contributor: user.person, creators: [user.person])
login_as(user)
get :new, params: { investigation_id: investigation }
@@ -54,7 +57,8 @@ class SnapshotsControllerTest < ActionController::TestCase
test 'can create investigation snapshot' do
user = FactoryBot.create(:user)
- investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person)
+ investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: user.person, creators: [user.person])
login_as(user)
assert_difference('Snapshot.count') do
@@ -67,7 +71,8 @@ class SnapshotsControllerTest < ActionController::TestCase
test 'can create study snapshot' do
user = FactoryBot.create(:user)
- study = FactoryBot.create(:study, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person)
+ study = FactoryBot.create(:study, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: user.person, creators: [user.person])
login_as(user)
assert_difference('Snapshot.count') do
@@ -80,7 +85,8 @@ class SnapshotsControllerTest < ActionController::TestCase
test 'can create assay snapshot' do
user = FactoryBot.create(:user)
- assay = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person)
+ assay = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: user.person, creators: [user.person])
login_as(user)
assert_difference('Snapshot.count') do
@@ -93,7 +99,8 @@ class SnapshotsControllerTest < ActionController::TestCase
test "can't create snapshot if no manage permissions" do
user = FactoryBot.create(:user)
- investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy))
+ investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ creators: [FactoryBot.create(:user).person])
login_as(user)
assert_no_difference('Snapshot.count') do
@@ -107,7 +114,8 @@ class SnapshotsControllerTest < ActionController::TestCase
test "can't create snapshot if not publicly accessible" do
user = FactoryBot.create(:user)
- investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy), contributor: user.person)
+ investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy),
+ contributor: user.person, creators: [user.person])
login_as(user)
assert_no_difference('Snapshot.count') do
@@ -119,6 +127,34 @@ class SnapshotsControllerTest < ActionController::TestCase
assert flash[:error].include?('accessible')
end
+ test "can't create snapshot if there are no creators" do
+ user = FactoryBot.create(:user)
+ investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: user.person, creators: [])
+ study = FactoryBot.create(:study, investigation: investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: user.person, creators: [])
+ assay = FactoryBot.create(:assay, study: study, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: user.person, creators: [])
+
+ login_as(user)
+ [investigation, study, assay].each do |snap|
+ assert snap.can_manage?(user)
+ assert snap.creators.empty?
+ type = snap.class.name.underscore
+ # Updating the request.path is needed so that @resource is correctly set, and the snapshots is created for the correct item in the loop
+ request.path = Seek::Util.routes.polymorphic_path([snap, :snapshots])
+ # Get preview
+ get :new, params: { "#{type}_id": snap.id }
+ assert_response :success
+ # Can't create snapshot
+ assert_no_difference('Snapshot.count') do
+ post :create, params: { "#{type}_id": snap.id }
+ end
+ assert_redirected_to Seek::Util.routes.polymorphic_path(snap)
+ assert flash[:error].include?('creator is required')
+ end
+ end
+
test 'can get snapshot show page' do
create_investigation_snapshot
login_as(@user)
@@ -543,14 +579,16 @@ class SnapshotsControllerTest < ActionController::TestCase
def create_investigation_snapshot
@user = FactoryBot.create(:user)
- @investigation = FactoryBot.create(:investigation, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person)
+ @investigation = FactoryBot.create(:investigation, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: @user.person, creators: [@user.person])
@snapshot = @investigation.create_snapshot
end
def create_study_snapshot
@user = FactoryBot.create(:user)
@investigation = FactoryBot.create(:investigation, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person)
- @study = FactoryBot.create(:study, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person)
+ @study = FactoryBot.create(:study, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: @user.person, creators: [@user.person])
@snapshot = @study.create_snapshot
end
@@ -558,7 +596,8 @@ def create_assay_snapshot
@user = FactoryBot.create(:user)
@investigation = FactoryBot.create(:investigation, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person)
@study = FactoryBot.create(:study, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person)
- @assay = FactoryBot.create(:assay, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person)
+ @assay = FactoryBot.create(:assay, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: @user.person, creators: [@user.person])
@snapshot = @assay.create_snapshot
end
end
diff --git a/test/functional/sops_controller_test.rb b/test/functional/sops_controller_test.rb
index 9a70d565ce..d6859c4011 100644
--- a/test/functional/sops_controller_test.rb
+++ b/test/functional/sops_controller_test.rb
@@ -1051,7 +1051,7 @@ def test_editing_doesnt_change_contributor
get :show, params: { id: sop }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
end
test 'should display license for current version' do
@@ -1062,11 +1062,11 @@ def test_editing_doesnt_change_contributor
get :show, params: { id: sop, version: 1 }
assert_response :success
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
get :show, params: { id: sop, version: sopv.version }
assert_response :success
- assert_select '.panel .panel-body a', text: 'CC0 1.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Zero v1.0 Universal'
end
test 'should update license' do
@@ -1079,7 +1079,7 @@ def test_editing_doesnt_change_contributor
assert_response :redirect
get :show, params: { id: sop }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share-Alike 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share Alike 4.0 International'
assert_equal 'CC-BY-SA-4.0', assigns(:sop).license
end
diff --git a/test/functional/studies_controller_test.rb b/test/functional/studies_controller_test.rb
index 70db123ffd..0ad7031d59 100644
--- a/test/functional/studies_controller_test.rb
+++ b/test/functional/studies_controller_test.rb
@@ -11,7 +11,7 @@ class StudiesControllerTest < ActionController::TestCase
def setup
login_as FactoryBot.create(:admin).user
end
-
+
test 'should get index' do
FactoryBot.create :study, policy: FactoryBot.create(:public_policy)
get :index
@@ -876,18 +876,17 @@ def test_should_show_investigation_tab
get :show, params: { id: study }
assert_response :success
- assert_select 'p',text:/Granny Smith/, count:2
+ assert_select 'div.custom_metadata',text:/Granny Smith/, count:2
end
test 'should create and update study with linked custom metadata type' do
cmt = FactoryBot.create(:role_custom_metadata_type)
login_as(FactoryBot.create(:person))
- linked_cmt = cmt.attributes_with_linked_custom_metadata_type.first.linked_custom_metadata_type
# test create
assert_difference('Study.count') do
- assert_difference('CustomMetadata.count',2) do
+ assert_difference('CustomMetadata.count') do
investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
study_attributes = { title: 'Alice in Wonderland', investigation_id: investigation.id }
cm_attributes = { custom_metadata_attributes: {
@@ -895,13 +894,9 @@ def test_should_show_investigation_tab
"role_email":"alice@email.com",
"role_phone":"0012345",
"role_name": {
- custom_metadata_type_id:linked_cmt.id,
- custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id,
- data:{
"first_name":"alice",
"last_name": "liddell"
}
- }
}
}
}
@@ -913,10 +908,10 @@ def test_should_show_investigation_tab
assert study = assigns(:study)
assert cm = study.custom_metadata
assert_equal cmt, cm.custom_metadata_type
- assert_equal "alice@email.com",cm.get_attribute_value('role_email')
- assert_equal '0012345',cm.get_attribute_value('role_phone')
- assert_equal 'alice', cm.linked_custom_metadatas.first.get_attribute_value('first_name')
- assert_equal 'liddell', cm.linked_custom_metadatas.first.get_attribute_value('last_name')
+ assert_equal "alice@email.com", cm.data['role_email']
+ assert_equal '0012345',cm.data['role_phone']
+ assert_equal 'alice', cm.data['role_name']['first_name']
+ assert_equal 'liddell', cm.data['role_name']['last_name']
# test show
get :show, params:{ id:study}
@@ -930,13 +925,8 @@ def test_should_show_investigation_tab
custom_metadata_attributes: {
custom_metadata_type_id: cmt.id, id:cm.id, data: {
"role_email":"rabbit@email.com",
- "role_name":{
- custom_metadata_type_id: linked_cmt.id,
- custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id,
- id: cm.linked_custom_metadatas.first.id,
- data:{
- "first_name":"rabbit"
- }
+ "role_name": {
+ "first_name":"rabbit"
}
}
}
@@ -945,62 +935,41 @@ def test_should_show_investigation_tab
end
end
-
assert new_study = assigns(:study)
assert_equal 'Alice Through the Looking Glass', new_study.title
- assert_equal 'rabbit@email.com', new_study.custom_metadata.get_attribute_value('role_email')
- assert_equal 'rabbit', new_study.custom_metadata.linked_custom_metadatas.first.get_attribute_value('first_name')
+ assert_equal 'rabbit@email.com', new_study.custom_metadata.data['role_email']
+ assert_equal 'rabbit', new_study.custom_metadata.data['role_name']['first_name']
end
- test 'should create and update study which has multiple custom metadata attributes, which link to the same custom metadata type' do
+ test 'should create and update study, whose custom metadata type contains attributes which link to the same custom metadata type' do
cmt = FactoryBot.create(:family_custom_metadata_type)
login_as(FactoryBot.create(:person))
linked_cmts = cmt.attributes_with_linked_custom_metadata_type
assert_difference('Study.count') do
- assert_difference('CustomMetadata.count',4) do
+ assert_difference('CustomMetadata.count') do
investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
study_attributes = { title: 'Family', investigation_id: investigation.id }
cm_attributes = { custom_metadata_attributes: {
custom_metadata_type_id: cmt.id, data: {
- "dad": {
- custom_metadata_type_id:linked_cmts[0].linked_custom_metadata_type.id,
- custom_metadata_attribute_id:linked_cmts[0].id,
- data:{
- "first_name":"john",
- "last_name": "liddell"
- }
- },
- "mom": {
- custom_metadata_type_id:linked_cmts[1].linked_custom_metadata_type.id,
- custom_metadata_attribute_id:linked_cmts[1].id,
- data:{
- "first_name":"lily",
- "last_name": "liddell"
- }
- },
- "child": {
- custom_metadata_type_id:linked_cmts[2].linked_custom_metadata_type.id,
- custom_metadata_attribute_id:linked_cmts[2].id,
- data:{
- "first_name":"alice",
- "last_name": "liddell"
- }
+ "dad":{"first_name":"john", "last_name":"liddell"},
+ "mom":{"first_name":"lily", "last_name":"liddell"},
+ "child":{"0":{"first_name":"alice", "last_name":"liddell"}}
}
}
}
- }
post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
end
end
assert study = assigns(:study)
- assert cm = study.custom_metadata
+ cm = study.custom_metadata
assert_equal cmt, cm.custom_metadata_type
-
- assert_equal "john",cm.linked_custom_metadatas[0].get_attribute_value('first_name')
- assert_equal "liddell",cm.linked_custom_metadatas[0].get_attribute_value('last_name')
- assert_equal "lily",cm.linked_custom_metadatas[1].get_attribute_value('first_name')
- assert_equal "alice",cm.linked_custom_metadatas[2].get_attribute_value('first_name')
+ data = cm.data
+ assert_equal %w[dad mom child], linked_cmts.map(&:title)
+ assert_equal "john",data["dad"]["first_name"]
+ assert_equal "liddell",data["dad"]['last_name']
+ assert_equal "lily",data["mom"]["first_name"]
+ assert_equal "alice",data["child"].first["first_name"]
# test show
get :show, params:{ id:study}
@@ -1012,22 +981,8 @@ def test_should_show_investigation_tab
put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass",
custom_metadata_attributes: {
custom_metadata_type_id: cmt.id, id:cm.id, data: {
- "dad": {
- custom_metadata_type_id:linked_cmts[0].linked_custom_metadata_type.id,
- custom_metadata_attribute_id:linked_cmts[0].id,
- data:{
- "first_name":"tom",
- "last_name": "liddell"
- }
- },
- "child": {
- custom_metadata_type_id:linked_cmts[2].linked_custom_metadata_type.id,
- custom_metadata_attribute_id:linked_cmts[2].id,
- data:{
- "first_name":"rabbit",
- "last_name": "wonderland"
- }
- }
+ "dad":{"first_name":"tom", "last_name":"liddell"},
+ "child":{"0":{"first_name":"rabbit", "last_name":"wonderland"},"1":{"first_name":"mad", "last_name":"hatter"}}
}
}
}
@@ -1035,49 +990,64 @@ def test_should_show_investigation_tab
end
end
assert new_study = assigns(:study)
- cm = new_study.custom_metadata
+ data = new_study.custom_metadata.data
- assert_equal "tom",cm.linked_custom_metadatas[0].get_attribute_value('first_name')
- assert_equal "liddell",cm.linked_custom_metadatas[0].get_attribute_value('last_name')
- assert_equal "lily",cm.linked_custom_metadatas[1].get_attribute_value('first_name')
- assert_equal "liddell",cm.linked_custom_metadatas[1].get_attribute_value('last_name')
- assert_equal "rabbit",cm.linked_custom_metadatas[2].get_attribute_value('first_name')
- assert_equal "wonderland",cm.linked_custom_metadatas[2].get_attribute_value('last_name')
+ assert_equal "tom",data["dad"]["first_name"]
+ assert_equal "liddell",data["dad"]['last_name']
+ assert_equal "lily",data["mom"]["first_name"]
+ assert_equal "liddell",data["mom"]['last_name']
+ assert_equal "rabbit",data["child"].first["first_name"]
+ assert_equal "wonderland",data["child"].first['last_name']
+ assert_equal "mad",data["child"].last["first_name"]
+ assert_equal "hatter",data["child"].last['last_name']
+ end
+ test 'should create and update study with multiple linked custom metadata types without entering non-required values' do
+ cmt = FactoryBot.create(:family_custom_metadata_type)
+ login_as(FactoryBot.create(:person))
+ assert_difference('Study.count') do
+ assert_difference('CustomMetadata.count') do
+ investigation = FactoryBot.create(:investigation, projects: User.current_user.person.projects, contributor: User.current_user.person)
+ study_attributes = { title: 'Family', investigation_id: investigation.id }
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id, data: {
+ "dad": { "first_name": "john", "last_name": "liddell" },
+ "mom": { "first_name": "lily", "last_name": "liddell" },
+ # the not reqiured attributes can be removed
+ "child": { "row-template": { "first_name": "alice", "last_name": "liddell" } }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ end
+ end
+ assert study = assigns(:study)
+ assert cm = study.custom_metadata
+ assert_equal cmt, cm.custom_metadata_type
+ assert_equal "john",cm.data["dad"]["first_name"]
+ assert_equal "liddell",cm.data["dad"]['last_name']
+ assert_equal "lily",cm.data["mom"]["first_name"]
+ assert_equal "liddell",cm.data["mom"]["last_name"]
+ assert_empty cm.data["child"]
end
test 'should create and update study with multiple linked custom metadata types' do
cmt = FactoryBot.create(:role_multiple_custom_metadata_type)
login_as(FactoryBot.create(:person))
- linked_name_cmt = cmt.attributes_with_linked_custom_metadata_type.first.linked_custom_metadata_type
- linked_addr_cmt = cmt.attributes_with_linked_custom_metadata_type.last.linked_custom_metadata_type
+
# test create
assert_difference('Study.count') do
- assert_difference('CustomMetadata.count',3) do
+ assert_difference('CustomMetadata.count') do
investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
study_attributes = { title: 'Alice in Wonderland', investigation_id: investigation.id }
cm_attributes = { custom_metadata_attributes: {
custom_metadata_type_id: cmt.id, data: {
"role_email":"alice@email.com",
"role_phone":"0012345",
- "role_name": {
- custom_metadata_type_id:linked_name_cmt.id,
- custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id,
- data:{
- "first_name":"alice",
- "last_name": "liddell"
- }
- },
- "role_address": {
- custom_metadata_type_id:linked_addr_cmt.id,
- custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.last.id,
- data:{
- "street":"wonder",
- "city": "land"
- }
- }
+ "role_name": {"first_name":"alice", "last_name": "liddell"},
+ "role_address": {"street":"wonder","city": "land" }
}
}
}
@@ -1088,12 +1058,12 @@ def test_should_show_investigation_tab
assert study = assigns(:study)
assert cm = study.custom_metadata
assert_equal cmt, cm.custom_metadata_type
- assert_equal "alice@email.com",cm.get_attribute_value('role_email')
- assert_equal '0012345',cm.get_attribute_value('role_phone')
- assert_equal 'alice', cm.linked_custom_metadatas.first.get_attribute_value('first_name')
- assert_equal 'liddell', cm.linked_custom_metadatas.first.get_attribute_value('last_name')
- assert_equal 'wonder', cm.linked_custom_metadatas.last.get_attribute_value('street')
- assert_equal 'land', cm.linked_custom_metadatas.last.get_attribute_value('city')
+ assert_equal "alice@email.com",cm.data['role_email']
+ assert_equal '0012345',cm.data['role_phone']
+ assert_equal 'alice', cm.data['role_name']['first_name']
+ assert_equal 'liddell', cm.data['role_name']['last_name']
+ assert_equal 'wonder', cm.data['role_address']['street']
+ assert_equal 'land', cm.data['role_address']['city']
# test show
get :show, params:{ id:study}
@@ -1108,12 +1078,7 @@ def test_should_show_investigation_tab
custom_metadata_type_id: cmt.id, id:cm.id, data: {
"role_email":"rabbit@email.com",
"role_name":{
- custom_metadata_type_id: linked_name_cmt.id,
- custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id,
- id: cm.linked_custom_metadatas.first.id,
- data:{
"first_name":"rabbit"
- }
}
}
}
@@ -1125,9 +1090,624 @@ def test_should_show_investigation_tab
assert new_study = assigns(:study)
assert_equal 'Alice Through the Looking Glass', new_study.title
- assert_equal 'rabbit@email.com', new_study.custom_metadata.get_attribute_value('role_email')
- assert_equal 'rabbit', new_study.custom_metadata.linked_custom_metadatas.first.get_attribute_value('first_name')
+ cm = new_study.custom_metadata
+ assert_equal 'rabbit@email.com', cm.data['role_email']
+ assert_equal 'rabbit', cm.data['role_name']['first_name']
+ end
+
+ test 'multiple levels of has many relationship' do
+ cmt = FactoryBot.create(:study_custom_metadata_type)
+ # linked_cmt = cmt.attributes_with_linked_custom_metadata_type.last.linked_custom_metadata_type
+ # linked_linked_cmt = linked_cmt.attributes_with_linked_custom_metadata_type.last.linked_custom_metadata_type
+ # linked_linked_linked_cmt = linked_linked_cmt.attributes_with_linked_custom_metadata_type.last.linked_custom_metadata_type
+ login_as(FactoryBot.create(:person))
+
+ assert_difference('Study.count') do
+ assert_difference('CustomMetadata.count') do
+ investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+ study_attributes = { title: 'my study', investigation_id: investigation.id }
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "study_title":"happy study",
+ "study_sites":{
+ "0":{
+ "study_site_name":"site1",
+ "study_site_location":"fairyland",
+ "participants":{
+ "0":{
+ "participant_name":{
+ "first_name":"alice",
+ "last_name":"liddell"
+ },
+ "participant_age":"7"
+ },
+ "1":{
+ "participant_name":{
+ "first_name":"pippi",
+ "last_name":"langstrumpf"
+ },
+ "participant_age":"9"
+ }
+ }
+ },
+ "1":{
+ "study_site_name":"site2",
+ "study_site_location":"space",
+ "participants":{
+ "0":{
+ "participant_name":{
+ "first_name":"arthur",
+ "last_name":"Dent"
+ },
+ "participant_age":"40"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+
+ end
+ end
+
+ assert study = assigns(:study)
+ assert cm = study.custom_metadata
+
+ assert_equal cmt, cm.custom_metadata_type
+ assert_equal "happy study",cm.data['study_title']
+ assert_equal "site1", cm.data['study_sites'][0]['study_site_name']
+ assert_equal "fairyland", cm.data['study_sites'][0]['study_site_location']
+ assert_equal "alice", cm.data['study_sites'][0]['participants'][0]['participant_name']['first_name']
+ assert_equal "langstrumpf", cm.data['study_sites'][0]['participants'][1]['participant_name']['last_name']
+ assert_equal "Dent", cm.data['study_sites'][1]['participants'][0]['participant_name']['last_name']
+ assert_equal "40", cm.data['study_sites'][1]['participants'][0]['participant_age']
+
+
+ # test show
+ get :show, params:{ id:study}
+ assert_response :success
+
+ # test update
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ put :update, params: {
+ id: study.id,
+ study: {
+ title: 'Updated Study',
+ custom_metadata_attributes: {
+ id:cm.id,
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "study_title":"happy study new",
+ "study_sites":{
+ "0":{
+ "study_site_name":"site1",
+ "study_site_location":"better fairyland",
+ "participants":{
+ "0":{
+ "participant_name":{
+ "first_name":"mad",
+ "last_name":"hatter"
+ },
+ "participant_age":"unknown"
+ },
+ "1":{
+ "participant_name":{
+ "first_name":"pippi",
+ "last_name":"langstrumpf"
+ },
+ "participant_age":"9"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+ assert new_study = assigns(:study)
+ assert cm = new_study.custom_metadata
+
+
+ assert_equal "site1", cm.data['study_sites'][0]['study_site_name']
+ assert_equal "better fairyland", cm.data['study_sites'][0]['study_site_location']
+ assert_equal "mad", cm.data['study_sites'][0]['participants'][0]['participant_name']['first_name']
+ assert_equal "hatter", cm.data['study_sites'][0]['participants'][0]['participant_name']['last_name']
+ assert_nil cm.data['study_sites'][1]
+
+
+ end
+
+
+ test 'when removing the study with the custom metadata, all its related custom metadtas should be destroyed' do
+ cmt = FactoryBot.create(:role_affiliation_custom_metadata_type)
+ login_as(FactoryBot.create(:person))
+
+ assert_difference('Study.count') do
+ assert_difference('CustomMetadata.count') do
+ investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+ study_attributes = { title: 'my study', investigation_id: investigation.id }
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name":"HITS",
+ "role_affiliation_identifiers":{
+ "0":{"identifier":"01f7bcy98", "scheme":"ROR"},
+ "1":{"identifier":"grid.424699.4", "scheme":"GRID"}
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+
+ end
+ end
+
+ assert study = assigns(:study)
+
+
+
+ assert_difference('Study.count', -1) do
+ assert_difference('CustomMetadata.count',-1) do
+ delete :destroy, params: { id: study.id }
+ end
+ end
+
+ assert !flash[:error]
+ assert_redirected_to studies_path
+ end
+
+
+
+ test 'should create and update study whose custom metadata type contains linked custom metadata multi type' do
+ cmt = FactoryBot.create(:role_affiliation_custom_metadata_type)
+ login_as(FactoryBot.create(:person))
+
+
+ # test create
+ assert_difference('Study.count') do
+ assert_difference('CustomMetadata.count') do
+ investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+ study_attributes = { title: 'my study', investigation_id: investigation.id }
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name":"HITS",
+ "role_affiliation_identifiers":{
+ "0":{ "identifier":"01f7bcy98", "scheme":"ROR"},
+ "1":{"identifier":"grid.424699.4", "scheme":"GRID"}
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ end
+ end
+
+
+ assert study = assigns(:study)
+ assert_redirected_to study_path(study)
+ study.reload
+
+
+ cm = study.custom_metadata
+ assert_equal cmt, cm.custom_metadata_type
+
+ assert_equal 'my study', study.title
+ assert_equal 'HITS',cm.data['role_affiliation_name']
+ assert_equal '01f7bcy98', cm.data['role_affiliation_identifiers'].first['identifier']
+ assert_equal 'ROR', cm.data['role_affiliation_identifiers'].first['scheme']
+ assert_equal 'grid.424699.4',cm.data['role_affiliation_identifiers'].last['identifier']
+ assert_equal 'GRID', cm.data['role_affiliation_identifiers'].last['scheme']
+
+ # test show
+ get :show, params:{ id:study}
+ assert_response :success
+
+ # test update
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ put :update, params: {
+ id: study.id,
+ study: {
+ title: 'Updated Study',
+ custom_metadata_attributes: {
+ id:cm.id,
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name": "University of Manchester",
+ "role_affiliation_identifiers": {
+ "0": { "identifier": "027m9bs27", "scheme": "ROR"},
+ "1": { "identifier": "grid.5379.8", "scheme": "GRID" }
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+
+ assert new_study = assigns(:study)
+ assert_redirected_to study_path(new_study)
+ new_study.reload
+ cm = new_study.custom_metadata
+ assert_equal cmt, cm.custom_metadata_type
+
+ assert_equal 'Updated Study', new_study.title
+ assert_equal 'University of Manchester',cm.data['role_affiliation_name']
+ assert_equal '027m9bs27', cm.data['role_affiliation_identifiers'].first['identifier']
+ assert_equal 'ROR', cm.data['role_affiliation_identifiers'].first['scheme']
+ assert_equal 'grid.5379.8', cm.data['role_affiliation_identifiers'].last['identifier']
+ assert_equal 'GRID', cm.data['role_affiliation_identifiers'].last['scheme']
+
+ # test update: adding an element in the array of linked custom metadatas
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ put :update, params: {
+ id: study.id,
+ study: {
+ title: 'Updated Study',
+ custom_metadata_attributes: {
+ id:cm.id,
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name": "University of Manchester",
+ "role_affiliation_identifiers": {
+ "0": { "identifier": "027m9bs27", "scheme": "ROR" },
+ "1": {"identifier": "grid.5379.8", "scheme": "GRID" },
+ "2": { "identifier": "0000 0001 2166 2407", "scheme": "ISNI" }
+
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+ assert new_study = assigns(:study)
+ assert_redirected_to study_path(new_study)
+ new_study.reload
+ cm = new_study.custom_metadata
+ assert_equal cmt, cm.custom_metadata_type
+
+
+
+ assert_equal 'University of Manchester',cm.data['role_affiliation_name']
+ assert_equal '027m9bs27', cm.data['role_affiliation_identifiers'][0]['identifier']
+ assert_equal 'ROR', cm.data['role_affiliation_identifiers'][0]['scheme']
+ assert_equal 'grid.5379.8', cm.data['role_affiliation_identifiers'][1]['identifier']
+ assert_equal 'GRID', cm.data['role_affiliation_identifiers'][1]['scheme']
+ assert_equal '0000 0001 2166 2407', cm.data['role_affiliation_identifiers'][2]['identifier']
+ assert_equal 'ISNI', cm.data['role_affiliation_identifiers'][2]['scheme']
+
+
+ # test update: adding an element and at the same time removing two elements in the array of linked custom metadatas
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+
+ put :update, params: {
+ id: study.id,
+ study: {
+ title: 'Updated Study',
+ custom_metadata_attributes: {
+ id:cm.id,
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name": "University of Manchester",
+ "role_affiliation_identifiers": {
+ "0": { "identifier": "027m9bs27", "scheme": "ROR" },
+ # new element
+ "1": { "identifier": "Q230899", "scheme": "Wikidata" }
+ }
+ }
+ }
+ }
+ }
+
+ end
+ end
+
+ assert new_study = assigns(:study)
+ assert_redirected_to study_path(new_study)
+ new_study.reload
+ cm = new_study.custom_metadata
+ assert_equal cmt, cm.custom_metadata_type
+
+ assert_equal 'Updated Study', new_study.title
+ assert_equal 'University of Manchester',cm.data['role_affiliation_name']
+ assert_equal '027m9bs27', cm.data['role_affiliation_identifiers'][0]['identifier']
+ assert_equal 'ROR', cm.data['role_affiliation_identifiers'][0]['scheme']
+ assert_equal 'Q230899', cm.data['role_affiliation_identifiers'][1]['identifier']
+ assert_equal 'Wikidata', cm.data['role_affiliation_identifiers'][1]['scheme']
+
+
+ end
+
+
+
+
+ test 'should not create a study and reload the form for incomplete details' do
+
+ cmt = FactoryBot.create(:role_affiliation_custom_metadata_type)
+ login_as(FactoryBot.create(:person))
+
+
+ # missing investigation
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ study_attributes = { title: 'my study' }
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name":"HITS",
+ "role_affiliation_identifiers":{
+ "0":{"identifier":"01f7bcy98", "scheme":"ROR"},
+ "1":{"identifier":"grid.424699.4", "scheme":"GRID"}
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ end
+ end
+
+ # should show error message
+ assert_select 'div#error_explanation' do
+ assert_select 'ul > li', text: "Investigation is blank or invalid"
+ end
+
+ # should reload the form with title
+ assert_select 'form#new_study' do
+ assert_select 'input#study_title[value=?]', 'my study'
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_name[value=?]', 'HITS'
+ end
+
+ # should reload the form with two role_affiliation_identifiers
+ assert_select 'div[id$="role-0"]' do
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_0_identifier[value=?]', '01f7bcy98'
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_0_scheme[value=?]', 'ROR'
+ end
+
+ assert_select 'div[id$="role-1"]' do
+
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_1_identifier[value=?]', 'grid.424699.4'
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_1_scheme[value=?]', 'GRID'
+ end
+
+
+ investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+
+ # missing required custom metadata value
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ study_attributes = { title: 'my study',investigation_id: investigation.id}
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name":"HITS",
+ "role_affiliation_identifiers":{
+ "0":{"identifier":"", "scheme":"ROR"},
+ "1":{"identifier":"grid.424699.4", "scheme":""}
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ end
+ end
+
+ # should show error message
+ assert_select 'div#error_explanation' do
+ assert_select 'ul > li', text: "Custom metadata role affiliation identifiers 1 identifier is required"
+ assert_select 'ul > li', text: "Custom metadata role affiliation identifiers 2 scheme is required"
+ end
+
+ # should reload the form with title
+ assert_select 'form#new_study' do
+ assert_select 'input#study_title[value=?]', 'my study'
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_name[value=?]', 'HITS'
+ end
+
+ # should reload the form with two role_affiliation_identifiers
+ assert_select 'div[id$="role-0"]' do
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_0_identifier[value=?]', ''
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_0_scheme[value=?]', 'ROR'
+ end
+
+ assert_select 'div[id$="role-1"]' do
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_1_identifier[value=?]', 'grid.424699.4'
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_1_scheme[value=?]', ''
+ end
+ end
+
+ test 'should not update a study and reload the form for incomplete details' do
+
+ cmt = FactoryBot.create(:role_affiliation_custom_metadata_type)
+ login_as(FactoryBot.create(:person))
+ investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+ study_attributes = { title: 'my study', investigation_id: investigation.id }
+
+
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name":"HITS",
+ "role_affiliation_identifiers":{
+ "0":{"identifier":"01f7bcy98", "scheme":"ROR"},
+ "1":{"identifier":"grid.424699.4", "scheme":"GRID"}
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+
+ assert study = assigns(:study)
+ assert_redirected_to study_path(study)
+ study.reload
+ cm = study.custom_metadata
+
+
+ # should not update when the investigation is deleted
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ put :update, params: {
+ id: study.id,
+ study: {
+ title: 'my new study title',
+ investigation_id: nil,
+ custom_metadata_attributes: {
+ id:cm.id,
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name": "University of Manchester",
+ "role_affiliation_identifiers": {
+ "0": { "identifier": "027m9bs27", "scheme": "ROR" },
+ # remove a previous row
+ # "1": { "identifier": "grid.5379.8", "scheme": "GRID" },
+
+ # add a new row
+ "2": {"identifier": "Q230899", "scheme": "Wikidata" }
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+ # the value of study in database should not change
+ assert_equal 'my study', study.title
+ assert_equal 'HITS',cm.data['role_affiliation_name']
+ assert_equal '01f7bcy98', cm.data['role_affiliation_identifiers'][0]['identifier']
+ assert_equal 'ROR', cm.data['role_affiliation_identifiers'][0]['scheme']
+ assert_equal 'grid.424699.4', cm.data['role_affiliation_identifiers'][1]['identifier']
+ assert_equal 'GRID', cm.data['role_affiliation_identifiers'][1]['scheme']
+
+
+ # should show error message
+ assert_select 'div#error_explanation' do
+ assert_select 'ul > li', text: "Investigation is blank or invalid"
+ end
+
+ # the form should load updated title value
+ assert_select 'form.edit_study' do
+ assert_select 'input#study_title[value=?]', 'my new study title'
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_name[value=?]', 'University of Manchester'
+ end
+
+ # the form should load updated role_affiliation_identifiers value
+ assert_select 'div[id$="role-0"]' do
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_0_identifier[value=?]', '027m9bs27'
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_0_scheme[value=?]', 'ROR'
+ end
+
+ # the form should not show removed value
+ assert_select 'input[value="grid.5379.8"]', count: 0
+ assert_select 'input[value="GRID"]', count: 0
+
+ # the form should show new value
+ assert_select "input[id^='study_custom_metadata_attributes_data_role_affiliation_identifiers_'][id$='_identifier'][value=?]",'Q230899'
+ assert_select "input[id^='study_custom_metadata_attributes_data_role_affiliation_identifiers_'][id$='_scheme'][value=?]",'Wikidata'
+
+ end
+
+ test 'should not update a study and reload the form for missing required linked custom metadata values' do
+
+ cmt = FactoryBot.create(:role_affiliation_custom_metadata_type)
+ login_as(FactoryBot.create(:person))
+
+ investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+ study_attributes = { title: 'my study', investigation_id: investigation.id }
+
+
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name":"HITS",
+ "role_affiliation_identifiers":{
+ "0":{"identifier":"01f7bcy98", "scheme":"ROR"},
+ "1":{"identifier":"grid.424699.4", "scheme":"GRID"}
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+
+ assert study = assigns(:study)
+ assert_redirected_to study_path(study)
+ study.reload
+ cm = study.custom_metadata
+
+ # should not update when the required linked custom metadata is missing
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ put :update, params: {
+ id: study.id,
+ study: {
+ title: 'my new study title',
+ custom_metadata_attributes: {
+ id:cm.id,
+ custom_metadata_type_id: cmt.id,
+ data: {
+ "role_affiliation_name": "University of Manchester",
+ "role_affiliation_identifiers": {
+ "0": { "identifier": "", "scheme": "ROR" },
+ # remove a previous row
+ # "1": {"identifier": "grid.5379.8", "scheme": "GRID" },
+ # add a new row
+ "2": { "identifier": "Q230899", "scheme": "Wikidata" }
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+ assert new_study = assigns(:study)
+
+
+ # the value of study in database should not change
+ assert_equal 'my study', study.title
+ assert_equal 'HITS',cm.data['role_affiliation_name']
+ assert_equal '01f7bcy98', cm.data['role_affiliation_identifiers'][0]['identifier']
+ assert_equal 'ROR', cm.data['role_affiliation_identifiers'][0]['scheme']
+ assert_equal 'grid.424699.4', cm.data['role_affiliation_identifiers'][1]['identifier']
+ assert_equal 'GRID',cm.data['role_affiliation_identifiers'][1]['scheme']
+
+ # should show error message
+ assert_select 'div#error_explanation' do
+ assert_select 'ul > li', text: "Custom metadata role affiliation identifiers 1 identifier is required"
+ end
+
+ # the form should load updated title value
+ assert_select 'form.edit_study' do
+ assert_select 'input#study_title[value=?]', 'my new study title'
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_name[value=?]', 'University of Manchester'
+ end
+
+ # the form should load updated role_affiliation_identifiers value
+ assert_select 'div[id$="role-0"]' do
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_0_identifier[value=?]', ''
+ assert_select 'input#study_custom_metadata_attributes_data_role_affiliation_identifiers_0_scheme[value=?]', 'ROR'
+ end
+
+ # the form should not show removed value
+ assert_select 'input[value="grid.5379.8"]', count: 0
+ assert_select 'input[value="GRID"]', count: 0
+
+ # the form should show new value
+ assert_select "input[id^='study_custom_metadata_attributes_data_role_affiliation_identifiers_'][id$='_identifier'][value=?]",'Q230899'
+ assert_select "input[id^='study_custom_metadata_attributes_data_role_affiliation_identifiers_'][id$='_scheme'][value=?]",'Wikidata'
end
@@ -1229,7 +1809,7 @@ def test_should_show_investigation_tab
policy: FactoryBot.create(:public_policy),
contributor: person)
get :show, params: { id: study.id }
-
+
assert_response :success
assert_select 'a[href=?]',
order_assays_study_path(study), count: 0
@@ -1394,4 +1974,22 @@ def test_should_show_investigation_tab
assert_equal 'my_tag', assigns(:study).tags_as_text_array.first
end
+ test 'should delete empty study with linked sample type' do
+ person = FactoryBot.create(:person)
+ study_source_sample_type = FactoryBot.create :linked_sample_type, contributor: person
+ study_sample_sample_type = FactoryBot.create :linked_sample_type, contributor: person
+ study = FactoryBot.create(:study,
+ policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission,contributor: person, access_type:Policy::EDITING)]),
+ sample_types: [study_source_sample_type, study_sample_sample_type],
+ contributor: person)
+
+ login_as(person)
+
+ assert_difference('SampleType.count', -2) do
+ assert_difference('Study.count', -1) do
+ delete :destroy, params: { id: study.id, return_to: '/single_pages/' }
+ end
+ end
+ end
+
end
diff --git a/test/functional/workflows_controller_test.rb b/test/functional/workflows_controller_test.rb
index b452baa3ea..5ef14327d8 100644
--- a/test/functional/workflows_controller_test.rb
+++ b/test/functional/workflows_controller_test.rb
@@ -220,7 +220,7 @@ def setup
get :show, params: { id: workflow }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
end
test 'should display license for current version' do
@@ -231,11 +231,11 @@ def setup
get :show, params: { id: workflow, version: 1 }
assert_response :success
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution 4.0 International'
get :show, params: { id: workflow, version: workflowv.version }
assert_response :success
- assert_select '.panel .panel-body a', text: 'CC0 1.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Zero v1.0 Universal'
end
test 'should update license' do
@@ -250,7 +250,7 @@ def setup
assert_response :redirect
get :show, params: { id: workflow }
- assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share-Alike 4.0'
+ assert_select '.panel .panel-body a', text: 'Creative Commons Attribution Share Alike 4.0 International'
assert_equal 'CC-BY-SA-4.0', assigns(:workflow).license
end
@@ -507,7 +507,7 @@ def setup
end
test 'handles error when generating diagram from CWL' do
- bad_generator = MiniTest::Mock.new
+ bad_generator = Minitest::Mock.new
def bad_generator.write_graph(struct)
raise 'oh dear'
end
@@ -1764,6 +1764,6 @@ def bad_generator.write_graph(struct)
get :show, params: { id: wf }
- assert_select 'a.lifemonitor-status[href=?]', "https://localhost:8443/workflow;uuid=#{wf.uuid}"
+ assert_select 'a.lifemonitor-status[href=?]', "https://app.lifemonitor.eu/workflow;uuid=#{wf.uuid}"
end
end
diff --git a/test/integration/api/sample_api_test.rb b/test/integration/api/sample_api_test.rb
index 3249d860a4..dd5c7ef49b 100644
--- a/test/integration/api/sample_api_test.rb
+++ b/test/integration/api/sample_api_test.rb
@@ -127,7 +127,7 @@ def setup
test 'create with multi sample and cv list' do
user_login
max_sample_type = FactoryBot.create(:max_sample_type)
- patients = [FactoryBot.create(:patient_sample), FactoryBot.create(:patient_sample)]
+ patients = [FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy)), FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy))]
params = {
"data": {
@@ -179,7 +179,7 @@ def setup
test 'create with multi sample and cv list - as array' do
user_login
max_sample_type = FactoryBot.create(:max_sample_type)
- patients = [FactoryBot.create(:patient_sample), FactoryBot.create(:patient_sample)]
+ patients = [FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy)), FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy))]
params = {
"data": {
diff --git a/test/integration/git_workflow_ro_crate_api_test.rb b/test/integration/git_workflow_ro_crate_api_test.rb
index b3b34c5fd9..c7e84558a4 100644
--- a/test/integration/git_workflow_ro_crate_api_test.rb
+++ b/test/integration/git_workflow_ro_crate_api_test.rb
@@ -103,6 +103,20 @@ class GitWorkflowRoCrateApiTest < ActionDispatch::IntegrationTest
end
end
+ test 'can identify license from URI' do
+ assert_difference('Workflow.count', 1) do
+ post workflows_path, params: {
+ ro_crate: fixture_file_upload('workflows/ro-crate-with-uri-license.crate.zip'),
+ workflow: {
+ project_ids: [@project.id]
+ }
+ }
+
+ assert_response :success
+ assert_equal 'MIT', assigns(:workflow).license
+ end
+ end
+
private
def login_as(user)
diff --git a/test/unit/activity_log_test.rb b/test/unit/activity_log_test.rb
index 4e9222f751..51e34b6135 100644
--- a/test/unit/activity_log_test.rb
+++ b/test/unit/activity_log_test.rb
@@ -82,7 +82,8 @@ class ActivityLogTest < ActiveSupport::TestCase
refute public_log.reload.can_render_link?
- assay = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy))
+ assay = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy),
+ creators: [FactoryBot.create(:person)])
snapshot = assay.create_snapshot
snapshot_log = FactoryBot.create(:activity_log, activity_loggable: snapshot, action: 'create', created_at: 2.hour.ago)
diff --git a/test/unit/assay_test.rb b/test/unit/assay_test.rb
index 106f225503..1a948b9a21 100644
--- a/test/unit/assay_test.rb
+++ b/test/unit/assay_test.rb
@@ -260,6 +260,25 @@ class AssayTest < ActiveSupport::TestCase
assert !one_assay_with_publication.can_delete?(User.current_user.person)
end
+ # Users shouldn't be able to delete assays populated with samples through their linked sample types
+ test 'can only delete assays with empty sample types' do
+ assay_sample_type = FactoryBot.create(:simple_sample_type, title: "Assay Sample Type with samples")
+ empty_sample_type = FactoryBot.create(:simple_sample_type, title: "Empty assay Sample Type")
+ assay_samples = (0..4).map do |i|
+ FactoryBot.create(:sample, title: "DNA Extract nr. #{i}", sample_type: assay_sample_type)
+ end
+
+ assay = FactoryBot.create(:assay, title: "First Assay", sample_type: assay_sample_type)
+ empty_assay = FactoryBot.create(:assay, title: "Empty assay", sample_type:empty_sample_type)
+
+ assert_equal(assay.sample_type.samples.size, 5)
+ assert(empty_assay.sample_type.samples.none?)
+
+ assert_equal(assay.state_allows_delete?, false)
+ assert_equal(empty_assay.state_allows_delete?, true)
+ end
+
+
test 'assets' do
assay = assays(:metabolomics_assay)
assert_equal 3, assay.assets.size, 'should be 2 sops and 1 data file'
diff --git a/test/unit/bio_schema/decorator_test.rb b/test/unit/bio_schema/decorator_test.rb
index 8e87095e53..03dcc49747 100644
--- a/test/unit/bio_schema/decorator_test.rb
+++ b/test/unit/bio_schema/decorator_test.rb
@@ -27,7 +27,7 @@ class DecoratorTest < ActiveSupport::TestCase
identifier = "http://localhost:3000/documents/#{document.id}"
assert_equal identifier, decorator.identifier
assert_equal %w[lorry yellow], decorator.keywords.split(',').collect(&:strip).sort
- assert_equal 'https://creativecommons.org/licenses/by/4.0/', decorator.license
+ assert_equal 'https://spdx.org/licenses/CC-BY-4.0', decorator.license
assert_equal 'application/pdf', decorator.content_type
project = document.projects.first
person = document.creators.first
diff --git a/test/unit/bio_schema/schema_ld_generation_test.rb b/test/unit/bio_schema/schema_ld_generation_test.rb
index 1a9a844db9..1806135cff 100644
--- a/test/unit/bio_schema/schema_ld_generation_test.rb
+++ b/test/unit/bio_schema/schema_ld_generation_test.rb
@@ -858,7 +858,7 @@ def setup
'name' => 'Workflows',
'url' => 'http://localhost:3000/workflows',
'keywords' => [],
- 'license' => 'https://creativecommons.org/publicdomain/zero/1.0/',
+ 'license' => 'https://spdx.org/licenses/CC0-1.0',
'creator' => [{'@type' => 'Organization',
'@id' => 'http://www.sysmo-db.org',
'name' => 'SysMO-DB',
@@ -892,7 +892,7 @@ def setup
'name' => 'Workflows',
'url' => 'http://localhost:3000/workflows',
'keywords' => [],
- 'license' => 'https://creativecommons.org/licenses/by/4.0/',
+ 'license' => 'https://spdx.org/licenses/CC-BY-4.0',
'creator' => [{ '@type' => 'Organization',
'@id' => 'http://www.sysmo-db.org',
'name' => 'SysMO-DB',
diff --git a/test/unit/custom_metadata_attribute_test.rb b/test/unit/custom_metadata_attribute_test.rb
index 62724238e0..db7ac4aaec 100644
--- a/test/unit/custom_metadata_attribute_test.rb
+++ b/test/unit/custom_metadata_attribute_test.rb
@@ -75,10 +75,6 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase
refute attribute.validate_value?(['Peter','Granny Smith'])
- attribute = CustomMetadataAttribute.new(title: 'role', sample_attribute_type: FactoryBot.create(:custom_metadata_sample_attribute_type),
- linked_custom_metadata_type: FactoryBot.create(:role_name_custom_metadata_type))
- assert attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?('first name')
- refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?(nil)
end
test 'validate value with required' do
@@ -111,6 +107,93 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase
end
+ test 'validate value for linked custom metadata type' do
+
+ attribute = CustomMetadataAttribute.new(title: 'role', sample_attribute_type: FactoryBot.create(:custom_metadata_sample_attribute_type),
+ linked_custom_metadata_type: FactoryBot.create(:role_name_custom_metadata_type))
+
+ assert attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?('first name')
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?('')
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?(nil)
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?([])
+
+
+ assert attribute.linked_custom_metadata_type.custom_metadata_attributes.last.validate_value?('last name')
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.last.validate_value?(nil)
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.last.validate_value?('')
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.last.validate_value?([])
+
+
+
+ attribute = CustomMetadataAttribute.new(title: 'study', sample_attribute_type: FactoryBot.create(:custom_metadata_sample_attribute_type),
+ linked_custom_metadata_type: FactoryBot.create(:study_custom_metadata_type))
+
+
+ # study_title required
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?([])
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?('')
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?(nil)
+ assert attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?('study_title')
+
+
+
+ study_sites_attr = attribute.linked_custom_metadata_type.custom_metadata_attributes.last
+
+
+ # study_sites not required
+ assert study_sites_attr.validate_value?([])
+ assert study_sites_attr.validate_value?('')
+ assert study_sites_attr.validate_value?(nil)
+
+ study_site_name_attr = study_sites_attr.linked_custom_metadata_type.custom_metadata_attributes[0]
+ study_site_location_attr = study_sites_attr.linked_custom_metadata_type.custom_metadata_attributes[1]
+ participants_attr = study_sites_attr.linked_custom_metadata_type.custom_metadata_attributes[2]
+
+ # study_site_name required
+ refute study_site_name_attr.validate_value?('')
+ refute study_site_name_attr.validate_value?(nil)
+ refute study_site_name_attr.validate_value?([])
+ assert study_site_name_attr.validate_value?('study_site_name')
+
+ # study_site_location not required
+ assert study_site_location_attr.validate_value?('')
+ assert study_site_location_attr.validate_value?(nil)
+ assert study_site_location_attr.validate_value?([])
+ assert study_site_location_attr.validate_value?('study_site_location')
+
+ # participants required
+ refute participants_attr.validate_value?('')
+ refute participants_attr.validate_value?(nil)
+ refute participants_attr.validate_value?([])
+
+ participant_name_attr = participants_attr.linked_custom_metadata_type.custom_metadata_attributes[0]
+ first_name_attr = participant_name_attr.linked_custom_metadata_type.custom_metadata_attributes[0]
+ last_name_attr = participant_name_attr.linked_custom_metadata_type.custom_metadata_attributes[1]
+
+ # first_name required
+ refute first_name_attr.validate_value?('')
+ refute first_name_attr.validate_value?(nil)
+ refute first_name_attr.validate_value?([])
+ assert first_name_attr.validate_value?('first_name')
+
+ # last_name required
+ refute last_name_attr.validate_value?('')
+ refute last_name_attr.validate_value?(nil)
+ refute last_name_attr.validate_value?([])
+ assert last_name_attr.validate_value?('first_name')
+
+ participant_age_attr = participants_attr.linked_custom_metadata_type.custom_metadata_attributes[1]
+
+ # participant_age not required
+ assert participant_age_attr.validate_value?('')
+ assert participant_age_attr.validate_value?(nil)
+ assert participant_age_attr.validate_value?([])
+ assert participant_age_attr.validate_value?('participant_age')
+
+
+ end
+
+
test 'accessor name' do
attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:datetime_sample_attribute_type)
assert_equal 'fish', attribute.accessor_name
diff --git a/test/unit/custom_metadata_test.rb b/test/unit/custom_metadata_test.rb
index bee68a90a4..34be1c72b9 100644
--- a/test/unit/custom_metadata_test.rb
+++ b/test/unit/custom_metadata_test.rb
@@ -59,6 +59,44 @@ class CustomMetadataTest < ActiveSupport::TestCase
assert_equal date, cm.get_attribute_value(:date)
end
+ test 'mass assign attribute with linked custom metadata' do
+ cm = CustomMetadata.new(custom_metadata_type: FactoryBot.build(:role_custom_metadata_type), item: FactoryBot.create(:study))
+ pp cm.update( data: {
+ "role_email":"alice@email.com",
+ "role_phone":"0012345",
+ "role_name": {
+ "first_name":"alice",
+ "last_name": "liddell"
+ }
+ }
+ )
+ assert cm.valid?
+ assert_equal 'alice@email.com', cm.get_attribute_value(:role_email)
+ assert_equal '0012345', cm.get_attribute_value(:role_phone)
+ assert_equal 'alice', cm.get_attribute_value(:role_name)["first_name"]
+ assert_equal 'liddell', cm.get_attribute_value(:role_name)["last_name"]
+ end
+
+ test 'mass assign attribute with multi linked custom metadatas' do
+ cm = CustomMetadata.new(custom_metadata_type: FactoryBot.build(:family_custom_metadata_type), item: FactoryBot.create(:study))
+ pp cm.update( data: {
+ "dad":{"first_name":"tom", "last_name":"liddell"},
+ "mom": { "first_name": "lily", "last_name": "liddell" },
+ "child":{
+ "0":{"first_name":"rabbit", "last_name":"wonderland"},
+ "1":{"first_name":"mad", "last_name":"hatter"}
+ }
+ }
+ )
+ assert cm.valid?
+ assert_equal 'tom', cm.get_attribute_value(:dad)["first_name"]
+ assert_equal 'liddell', cm.get_attribute_value(:dad)["last_name"]
+ assert_equal 'lily', cm.get_attribute_value(:mom)["first_name"]
+ assert_equal 'rabbit', cm.get_attribute_value(:child).first["first_name"]
+ assert_equal 'mad', cm.get_attribute_value(:child).last["first_name"]
+ end
+
+
test 'mass assignment mismatch attributes' do
cm = simple_test_object
date = Time.now.to_s
@@ -157,6 +195,25 @@ class CustomMetadataTest < ActiveSupport::TestCase
end
end
+ test 'mass assign attributes with the linked custom metadata' do
+ cm = CustomMetadata.new(custom_metadata_type: FactoryBot.build(:family_custom_metadata_type), item: FactoryBot.create(:study))
+ pp cm.update( data: {
+ "dad":{"first_name":"tom", "last_name":"liddell"},
+ "mom": { "first_name": "lily", "last_name": "liddell" },
+ "child":{
+ "0":{"first_name":"rabbit", "last_name":"wonderland"},
+ "1":{"first_name":"mad", "last_name":"hatter"}
+ }
+ }
+ )
+ assert cm.valid?
+ assert_equal 'tom', cm.get_attribute_value('dad')["first_name"]
+ assert_equal 'liddell', cm.get_attribute_value('dad')["last_name"]
+ assert_equal 'lily', cm.get_attribute_value('mom')["first_name"]
+ assert_equal 'rabbit', cm.get_attribute_value('child').first["first_name"]
+ assert_equal 'mad', cm.get_attribute_value('child').last["first_name"]
+ end
+
test 'associated metadata destroyed with study' do
contributor = FactoryBot.create(:person)
User.with_current_user(contributor.user) do
@@ -217,6 +274,8 @@ class CustomMetadataTest < ActiveSupport::TestCase
end
end
+
+
private
def simple_test_object
diff --git a/test/unit/datacite_metadata_test.rb b/test/unit/datacite_metadata_test.rb
index febea44fbb..c43c76154e 100644
--- a/test/unit/datacite_metadata_test.rb
+++ b/test/unit/datacite_metadata_test.rb
@@ -8,11 +8,12 @@ class DataciteMetadataTest < ActiveSupport::TestCase
User.current_user = contributor.user
@investigation = FactoryBot.create(:investigation, title: 'i1', description: 'not blank',
- policy: FactoryBot.create(:downloadable_public_policy), contributor:contributor)
+ policy: FactoryBot.create(:downloadable_public_policy),
+ contributor: contributor, creators: [contributor])
@study = FactoryBot.create(:study, title: 's1', investigation: @investigation, contributor: @investigation.contributor,
- policy: FactoryBot.create(:downloadable_public_policy))
+ policy: FactoryBot.create(:downloadable_public_policy), creators: [contributor])
@assay = FactoryBot.create(:assay, title: 'a1', study: @study, contributor: @investigation.contributor,
- policy: FactoryBot.create(:downloadable_public_policy))
+ policy: FactoryBot.create(:downloadable_public_policy), creators: [contributor])
@assay2 = FactoryBot.create(:assay, title: 'a2', study: @study, contributor: @investigation.contributor,
policy: FactoryBot.create(:downloadable_public_policy))
@data_file = FactoryBot.create(:data_file, title: 'df1', contributor: @investigation.contributor,
diff --git a/test/unit/helpers/dynamic_table_helper_test.rb b/test/unit/helpers/dynamic_table_helper_test.rb
index 62a4eb3cce..d1828e1966 100644
--- a/test/unit/helpers/dynamic_table_helper_test.rb
+++ b/test/unit/helpers/dynamic_table_helper_test.rb
@@ -9,33 +9,27 @@ class DynamicTableHelperTest < ActionView::TestCase
User.with_current_user(person.user) do
inv = FactoryBot.create(:investigation, projects: [project], contributor: person)
- sample_a1 = FactoryBot.create(:patient_sample)
+ sample_a1 = FactoryBot.create(:patient_sample, contributor: person)
type_a = sample_a1.sample_type
- sample_a2 = FactoryBot.create(:patient_sample, sample_type: type_a)
- sample_a3 = FactoryBot.create(:patient_sample, sample_type: type_a)
+ sample_a2 = FactoryBot.create(:patient_sample, sample_type: type_a, contributor: person)
+ sample_a3 = FactoryBot.create(:patient_sample, sample_type: type_a, contributor: person)
type_b = FactoryBot.create(:multi_linked_sample_type, project_ids: [project.id])
type_b.sample_attributes.last.linked_sample_type = type_a
type_b.save!
- sample_b1 = Sample.new(sample_type: type_b, project_ids: [project.id])
- sample_b1.set_attribute_value(:title, 'sample_b1')
- sample_b1.set_attribute_value(:patient, [sample_a1.id])
- disable_authorization_checks { sample_b1.save! }
+ sample_b1 = type_b.samples.create!(data: { title: 'sample_b1', patient: [sample_a1.id] },
+ sample_type: type_b, project_ids: [project.id])
- sample_b2 = Sample.new(sample_type: type_b, project_ids: [project.id])
- sample_b2.set_attribute_value(:title, 'sample_b2')
- sample_b2.set_attribute_value(:patient, [sample_a2.id])
- disable_authorization_checks { sample_b2.save! }
+ sample_b2 = type_b.samples.create!(data: { title: 'sample_b2', patient: [sample_a2.id] },
+ sample_type: type_b, project_ids: [project.id])
type_c = FactoryBot.create(:multi_linked_sample_type, project_ids: [project.id])
type_c.sample_attributes.last.linked_sample_type = type_b
type_c.save!
- sample_c1 = Sample.new(sample_type: type_c, project_ids: [project.id])
- sample_c1.set_attribute_value(:title, 'sample_c1')
- sample_c1.set_attribute_value(:patient, [sample_b1.id])
- disable_authorization_checks { sample_c1.save! }
+ sample_c1 = type_c.samples.create!(data: { title: 'sample_c1', patient: [sample_b1.id] },
+ sample_type: type_c, project_ids: [project.id])
study = FactoryBot.create(:study, investigation: inv, contributor: person, sample_types: [type_a, type_b])
assay = FactoryBot.create(:assay, study: study, contributor: person, sample_type: type_c, position: 1)
diff --git a/test/unit/helpers/homes_helper_test.rb b/test/unit/helpers/homes_helper_test.rb
index c8767388d0..90613f5530 100644
--- a/test/unit/helpers/homes_helper_test.rb
+++ b/test/unit/helpers/homes_helper_test.rb
@@ -60,8 +60,10 @@ def setup
test 'should handle snapshots for download and recently added' do
person = FactoryBot.create(:person)
- snapshot1 = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), contributor: person).create_snapshot
- snapshot2 = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy), contributor: person).create_snapshot
+ snapshot1 = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: person, creators: [person]).create_snapshot
+ snapshot2 = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: person, creators: [person]).create_snapshot
FactoryBot.create(:activity_log, action: 'create', activity_loggable: snapshot1, created_at: 1.day.ago, culprit: person.user)
FactoryBot.create(:activity_log, action: 'download', activity_loggable: snapshot2, created_at: 1.day.ago, culprit: person.user)
diff --git a/test/unit/helpers/resource_list_helper_test.rb b/test/unit/helpers/resource_list_helper_test.rb
index d9dd811ed2..cd356228f8 100644
--- a/test/unit/helpers/resource_list_helper_test.rb
+++ b/test/unit/helpers/resource_list_helper_test.rb
@@ -24,7 +24,7 @@ class ResourceListHelperTest < ActionView::TestCase
assert_equal link_to(data_file.contributor.name, data_file.contributor),
resource_list_column_display_value(data_file, 'contributor')
- assert_equal link_to('Creative Commons Attribution 4.0', 'https://creativecommons.org/licenses/by/4.0/', target: :_blank),
+ assert_equal link_to('Creative Commons Attribution 4.0 International', 'https://spdx.org/licenses/CC-BY-4.0', target: :_blank),
resource_list_column_display_value(data_file, 'license')
assert_match(/href="#{data_file_path(data_file)}".*#{data_file.title}/,
diff --git a/test/unit/investigation_test.rb b/test/unit/investigation_test.rb
index bbdd8b4744..c1be4a2554 100644
--- a/test/unit/investigation_test.rb
+++ b/test/unit/investigation_test.rb
@@ -144,7 +144,9 @@ class InvestigationTest < ActiveSupport::TestCase
end
test 'can create snapshot of investigation' do
- investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy))
+ person = FactoryBot.create(:person)
+ investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy),
+ contributor: person, creators: [person])
FactoryBot.create(:study, contributor: investigation.contributor)
snapshot = nil
diff --git a/test/unit/isa_exporter_test.rb b/test/unit/isa_exporter_test.rb
index 0abcd0ca5f..96936387f1 100644
--- a/test/unit/isa_exporter_test.rb
+++ b/test/unit/isa_exporter_test.rb
@@ -24,21 +24,22 @@ class IsaExporterTest < ActionController::TestCase
title: 'PARENT 1',
sample_type: type_1,
project_ids: [project.id],
+ policy: FactoryBot.create(:public_policy),
data: {
the_title: 'PARENT 1'
}
- child_1 = Sample.new(sample_type: type_2, project_ids: [project.id])
+ child_1 = Sample.new(sample_type: type_2, project_ids: [project.id], policy:FactoryBot.create(:public_policy))
child_1.set_attribute_value(:patient, [parent.id])
child_1.set_attribute_value(:title, 'CHILD 1')
child_1.save!
- child_2 = Sample.new(sample_type: type_3, project_ids: [project.id])
+ child_2 = Sample.new(sample_type: type_3, project_ids: [project.id], policy:FactoryBot.create(:public_policy))
child_2.set_attribute_value(:patient, [child_1.id])
child_2.set_attribute_value(:title, 'CHILD 2')
child_2.save!
- child_3 = Sample.new(sample_type: type_4, project_ids: [project.id])
+ child_3 = Sample.new(sample_type: type_4, project_ids: [project.id], policy:FactoryBot.create(:public_policy))
child_3.set_attribute_value(:patient, [child_2.id])
child_3.set_attribute_value(:title, 'CHILD 3')
child_3.save!
@@ -54,6 +55,7 @@ class IsaExporterTest < ActionController::TestCase
title: 'PARENT 2',
sample_type: type_1,
project_ids: [project.id],
+ policy:FactoryBot.create(:public_policy),
data: {
the_title: 'PARENT 2'
}
diff --git a/test/unit/isa_graph_generator_test.rb b/test/unit/isa_graph_generator_test.rb
index 20eb3c9a73..e2f4d9c884 100644
--- a/test/unit/isa_graph_generator_test.rb
+++ b/test/unit/isa_graph_generator_test.rb
@@ -137,4 +137,44 @@ class IsaGraphGeneratorTest < ActiveSupport::TestCase
refute_includes result[:nodes].map(&:object), investigation2
refute_includes result[:nodes].map(&:object), investigation3
end
+
+ test 'shows direct associations rather than related' do
+ person = FactoryBot.create(:person)
+ publication = FactoryBot.create(:publication)
+ publication2 = FactoryBot.create(:publication)
+ assay = FactoryBot.create(:assay, contributor: person, publications: [publication])
+ disable_authorization_checks { assay.study.publications << publication2 }
+
+ assert_equal [publication], assay.publications
+ assert_equal [publication], assay.related_publications
+
+ assert_equal [publication2], assay.study.publications
+ assert_equal [publication, publication2].sort, assay.study.related_publications.sort
+
+ assert_empty assay.study.investigation.publications
+ assert_equal [publication, publication2].sort, assay.study.investigation.related_publications.sort
+
+ generator = Seek::IsaGraphGenerator.new(assay)
+ result = generator.generate(parent_depth: nil)
+
+ assert_equal 5, result[:nodes].count
+ assert_equal 4, result[:edges].count
+
+ assay_pub_edges = result[:edges].select { |edge| edge.include?(assay) && edge.include?(publication) }
+ assert_equal 1, assay_pub_edges.count
+ assay_pub_edges = result[:edges].select { |edge| edge.include?(assay) && edge.include?(publication2) }
+ assert_empty assay_pub_edges
+
+ study_pub_edges = result[:edges].select { |edge| edge.include?(assay.study) && edge.include?(publication) }
+ assert_empty study_pub_edges
+
+ study_pub_edges = result[:edges].select { |edge| edge.include?(assay.study) && edge.include?(publication2) }
+ assert_equal 1, study_pub_edges.count
+
+ inv_pub_edges = result[:edges].select { |edge| edge.include?(assay.study.investigation) && edge.include?(publication) }
+ assert_empty inv_pub_edges
+ inv_pub_edges = result[:edges].select { |edge| edge.include?(assay.study.investigation) && edge.include?(publication2) }
+ assert_empty inv_pub_edges
+
+ end
end
diff --git a/test/unit/jobs/regular_maintenace_job_test.rb b/test/unit/jobs/regular_maintenace_job_test.rb
index 574b283ba2..46ddbd6c0f 100644
--- a/test/unit/jobs/regular_maintenace_job_test.rb
+++ b/test/unit/jobs/regular_maintenace_job_test.rb
@@ -15,7 +15,7 @@ def setup
travel_to(9.hours.ago) do
to_go = FactoryBot.create(:content_blob)
keep1 = FactoryBot.create(:data_file).content_blob
- keep2 = FactoryBot.create(:investigation).create_snapshot.content_blob
+ keep2 = FactoryBot.create(:investigation, creators: [FactoryBot.create(:person)]).create_snapshot.content_blob
keep3 = FactoryBot.create(:strain_sample_type).content_blob
end
diff --git a/test/unit/license_test.rb b/test/unit/license_test.rb
index f654981899..320807399a 100644
--- a/test/unit/license_test.rb
+++ b/test/unit/license_test.rb
@@ -2,8 +2,10 @@
class LicenseTest < ActiveSupport::TestCase
setup do
- @zenodo = Seek::License.zenodo[:all]
- @od = Seek::License.open_definition[:all]
+ @zenodo = Seek::License.zenodo
+ @od = Seek::License.open_definition
+ @spdx = Seek::License.spdx
+ @combined = Seek::License.combined
end
test 'can find licenses in zenodo vocab' do
@@ -25,11 +27,6 @@ class LicenseTest < ActiveSupport::TestCase
assert license.is_a?(Seek::License)
assert_equal 'Creative Commons Attribution 4.0', license.title
assert_equal 'https://creativecommons.org/licenses/by/4.0/', license.url
-
- license = Seek::License.find('CC-BY-4.0')
- assert license.is_a?(Seek::License)
- assert_equal 'Creative Commons Attribution 4.0', license.title
- assert_equal 'https://creativecommons.org/licenses/by/4.0/', license.url
end
test 'can find licenses as hash in opendefinition vocab' do
@@ -39,6 +36,69 @@ class LicenseTest < ActiveSupport::TestCase
assert_equal 'https://creativecommons.org/licenses/by/4.0/', license['url']
end
+ test 'can find licenses in spdx vocab' do
+ license = Seek::License.find('CC-BY-4.0', @spdx)
+ assert license.is_a?(Seek::License)
+ assert_equal 'Creative Commons Attribution 4.0 International', license.title
+ assert_equal 'https://spdx.org/licenses/CC-BY-4.0', license.url
+
+ license = Seek::License.find('Zed', @spdx)
+ assert license.is_a?(Seek::License)
+ assert_equal 'Zed License', license.title
+ assert_equal 'https://spdx.org/licenses/Zed', license.url
+ end
+
+ test 'can find licenses as hash in spdx vocab' do
+ license = Seek::License.find_as_hash('Zed', @spdx)
+ assert license.is_a?(Hash)
+ assert_equal 'Zed License', license['title']
+ assert_equal 'https://spdx.org/licenses/Zed', license['url']
+ end
+
+ test 'can find licenses in combined vocab' do
+ license = Seek::License.find('other-at', @combined)
+ assert license.is_a?(Seek::License)
+ assert_equal 'Other (Attribution)', license.title
+ assert_equal '', license.url
+
+ license = Seek::License.find('notspecified', @combined)
+ assert license.is_a?(Seek::License)
+ assert_equal 'No license - no permission to use unless the owner grants a licence', license.title
+ assert_equal 'https://choosealicense.com/no-permission/', license.url
+
+ license = Seek::License.find('Zed', @combined)
+ assert license.is_a?(Seek::License)
+ assert_equal 'Zed License', license.title
+ assert_equal 'https://spdx.org/licenses/Zed', license.url
+
+ license = Seek::License.find('CC-BY-4.0')
+ assert license.is_a?(Seek::License)
+ assert_equal 'Creative Commons Attribution 4.0 International', license.title
+ assert_equal 'https://spdx.org/licenses/CC-BY-4.0', license.url
+ end
+
+ test 'can find licenses as hash in combined vocab' do
+ license = Seek::License.find_as_hash('other-at', @combined)
+ assert license.is_a?(Hash)
+ assert_equal 'Other (Attribution)', license['title']
+ assert_equal '', license['url']
+
+ license = Seek::License.find_as_hash('notspecified', @combined)
+ assert license.is_a?(Hash)
+ assert_equal 'No license - no permission to use unless the owner grants a licence', license['title']
+ assert_equal 'https://choosealicense.com/no-permission/', license['url']
+
+ license = Seek::License.find_as_hash('Zed', @combined)
+ assert license.is_a?(Hash)
+ assert_equal 'Zed License', license['title']
+ assert_equal 'https://spdx.org/licenses/Zed', license['url']
+
+ license = Seek::License.find_as_hash('CC-BY-4.0')
+ assert license.is_a?(Hash)
+ assert_equal 'Creative Commons Attribution 4.0 International', license['title']
+ assert_equal 'https://spdx.org/licenses/CC-BY-4.0', license['url']
+ end
+
test 'returns nil when cannot find license' do
assert_nil Seek::License.find('license-to-kill')
assert_nil Seek::License.find('cc-by', @od)
@@ -46,14 +106,14 @@ class LicenseTest < ActiveSupport::TestCase
end
test 'override notspecified text and url' do
- refute_nil (license = Seek::License.find('notspecified'))
+ refute_nil(license = Seek::License.find('notspecified'))
assert license.is_a?(Seek::License)
assert license.is_null_license?
assert_equal 'No license - no permission to use unless the owner grants a licence',license['title']
assert_equal 'https://choosealicense.com/no-permission/',license['url']
#double check the main hash
- license_json = Seek::License.open_definition[:all].find{|x| x['id']=='notspecified'}
+ license_json = Seek::License.open_definition['notspecified']
assert_equal license,Seek::License.new(license_json)
end
@@ -64,7 +124,7 @@ class LicenseTest < ActiveSupport::TestCase
sop.license = 'CCZZ'
refute sop.valid?
assert_equal 1,sop.errors.count
- assert sop.errors.added?(:license, "isn't a valid license ID")
+ assert sop.errors.added?(:license, "isn't a recognized license")
#allow blank
sop.license=nil
@@ -77,4 +137,26 @@ class LicenseTest < ActiveSupport::TestCase
assert sop.valid?
end
+ test 'lookup license ID from URI' do
+ assert_equal 'CC-BY-4.0', Seek::License.uri_to_id('https://spdx.org/licenses/CC-BY-4.0.html')
+ assert_equal 'CC-BY-4.0', Seek::License.uri_to_id('https://spdx.org/licenses/CC-BY-4.0')
+ assert_equal 'CC-BY-4.0', Seek::License.uri_to_id('https://creativecommons.org/licenses/by/4.0/')
+ assert_equal 'CC-BY-4.0', Seek::License.uri_to_id('https://creativecommons.org/licenses/by/4.0/legalcode')
+
+ assert_equal 'MIT-open-group', Seek::License.uri_to_id('https://gitlab.freedesktop.org/xorg/app/iceauth/-/blob/master/COPYING')
+
+ assert_nil Seek::License.uri_to_id('https://creativecommons.org/licenses/by/5.0')
+ end
+
+ test 'set license via URI' do
+ sop = FactoryBot.create(:sop, license: 'https://creativecommons.org/licenses/by/4.0/')
+ assert sop.valid?
+ assert_equal 'CC-BY-4.0', sop.license
+
+ sop.license = 'CCZZ'
+ refute sop.valid?
+ assert_equal 1,sop.errors.count
+ assert sop.errors.added?(:license, "isn't a recognized license")
+ assert_equal 'CCZZ', sop.license
+ end
end
diff --git a/test/unit/policy_test.rb b/test/unit/policy_test.rb
index 86258d5cf2..6db205c927 100644
--- a/test/unit/policy_test.rb
+++ b/test/unit/policy_test.rb
@@ -196,31 +196,27 @@ class PolicyTest < ActiveSupport::TestCase
test 'policy not destroyed if still referenced by assets' do
policy = FactoryBot.create(:public_policy)
- sample_type = FactoryBot.create(:strain_sample_type)
- data_file = FactoryBot.create(:strain_sample_data_file, policy: policy)
- samples = data_file.extract_samples(sample_type, true).select(&:persisted?)
- sample = samples.first
+ sop1 = FactoryBot.create(:sop, policy: policy)
+ sop2 = FactoryBot.create(:sop, policy: policy)
- assert_equal sample.policy, data_file.policy
+ assert_equal sop1.policy, sop2.policy
assert_no_difference('Policy.count') do
- disable_authorization_checks { data_file.destroy }
+ disable_authorization_checks { sop1.destroy }
end
- assert_not_nil sample.reload.policy
+ assert_not_nil sop2.reload.policy
assert_not_nil Policy.find_by_id(policy.id)
end
test 'policy destroyed when no longer referenced' do
policy = FactoryBot.create(:public_policy)
- sample_type = FactoryBot.create(:strain_sample_type)
- data_file = FactoryBot.create(:strain_sample_data_file, policy: policy)
- samples = data_file.extract_samples(sample_type, true).select(&:persisted?)
-
- disable_authorization_checks { data_file.destroy }
+ sop1 = FactoryBot.create(:sop, policy: policy)
+ sop2 = FactoryBot.create(:sop, policy: policy)
+ sops = [sop1, sop2]
assert_difference('Policy.count', -1) do
- disable_authorization_checks { samples.each(&:destroy) }
+ disable_authorization_checks { sops.each(&:destroy) }
end
assert_nil Policy.find_by_id(policy.id)
diff --git a/test/unit/sample_test.rb b/test/unit/sample_test.rb
index 1acb660fd8..310bc1bcb3 100644
--- a/test/unit/sample_test.rb
+++ b/test/unit/sample_test.rb
@@ -1,6 +1,7 @@
require 'test_helper'
class SampleTest < ActiveSupport::TestCase
+
test 'validation' do
sample = FactoryBot.create :sample, title: 'fish', sample_type: FactoryBot.create(:simple_sample_type), data: { the_title: 'fish' }
assert sample.valid?
@@ -527,7 +528,7 @@ class SampleTest < ActiveSupport::TestCase
test 'linked sample as title' do
# setup sample type, to be linked to patient sample type
- patient = FactoryBot.create(:patient_sample)
+ patient = FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy))
assert_equal 'Fred Bloggs', patient.title
linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [FactoryBot.create(:project).id])
linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type
@@ -607,7 +608,7 @@ class SampleTest < ActiveSupport::TestCase
test 'set linked sample by id' do
# setup sample type, to be linked to patient sample type
- patient = FactoryBot.create(:patient_sample)
+ patient = FactoryBot.create(:patient_sample, policy: FactoryBot.create(:public_policy))
linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [FactoryBot.create(:project).id])
linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type
linked_sample_type.save!
@@ -626,7 +627,7 @@ class SampleTest < ActiveSupport::TestCase
test 'set linked sample by title' do
# setup sample type, to be linked to patient sample type
- patient = FactoryBot.create(:patient_sample)
+ patient = FactoryBot.create(:patient_sample, policy: FactoryBot.create(:public_policy))
linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [FactoryBot.create(:project).id])
linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type
@@ -695,10 +696,10 @@ class SampleTest < ActiveSupport::TestCase
end
end
- test 'samples extracted from a data file cannot be edited' do
+ test 'samples extracted from a data file can be edited' do
sample = FactoryBot.create(:sample_from_file)
- refute sample.state_allows_edit?
+ assert sample.state_allows_edit?
end
test 'samples not extracted from a data file can be edited' do
@@ -707,45 +708,42 @@ class SampleTest < ActiveSupport::TestCase
assert sample.state_allows_edit?
end
- test 'extracted samples inherit permissions from data file' do
+ test 'extracted samples copy permissions from data file' do
person = FactoryBot.create(:person)
other_person = FactoryBot.create(:person)
sample_type = FactoryBot.create(:strain_sample_type)
- data_file = FactoryBot.create(:strain_sample_data_file, policy: FactoryBot.create(:public_policy), contributor: person)
+ data_file = FactoryBot.create(:strain_sample_data_file, contributor: person, policy: FactoryBot.create(:private_policy,
+ permissions:[FactoryBot.create(:permission, contributor:other_person, access_type:Policy::MANAGING)]))
+
+ # sanity check - data_file policy
+ assert_equal Policy::PRIVATE, data_file.policy.access_type
+ assert_equal 1, data_file.policy.permissions.count
+ assert_equal other_person, data_file.policy.permissions.first.contributor
+ assert_equal Policy::MANAGING, data_file.policy.permissions.first.access_type
samples = data_file.extract_samples(sample_type, true)
sample = samples.first
+ sample2 = samples.second
- assert sample.can_view?(person.user)
- assert sample.can_view?(nil)
- assert sample.can_view?(other_person.user)
+ # check samples *copied* policy and permissions
+ assert_equal Policy::PRIVATE, sample.policy.access_type
+ assert_equal 1, sample.policy.permissions.count
+ assert_equal other_person, sample.policy.permissions.first.contributor
+ assert_equal Policy::MANAGING, sample.policy.permissions.first.access_type
+ # check policies are independent
+ refute_equal sample.policy, data_file.policy
+ refute_equal sample.policy, sample2.policy
- policy = data_file.policy
disable_authorization_checks do
- policy.access_type = Policy::NO_ACCESS
- policy.save
- sample.reload
+ sample.policy.access_type = Policy::ACCESSIBLE
+ sample.policy.save
end
-
- assert sample.can_view?(person.user)
- refute sample.can_view?(nil)
- refute sample.can_view?(other_person.user)
- end
-
- test 'sample policy persists even after originating data file deleted' do
- person = FactoryBot.create(:person)
- sample_type = FactoryBot.create(:strain_sample_type)
- data_file = FactoryBot.create(:strain_sample_data_file, policy: FactoryBot.create(:public_policy), contributor: person)
- samples = data_file.extract_samples(sample_type, true)
- sample = samples.first
-
- assert_equal sample.policy_id, data_file.policy_id
-
- old_policy_id = sample.policy_id
- disable_authorization_checks { data_file.destroy }
-
- assert_not_nil sample.reload.policy
- assert_equal old_policy_id, sample.policy_id
+ data_file.reload
+ sample.reload
+ sample2.reload
+ refute data_file.can_view?(nil)
+ assert sample.can_view?(nil)
+ refute sample2.can_view?(nil)
end
test 'extracted samples inherit projects from data file' do
@@ -1119,8 +1117,8 @@ class SampleTest < ActiveSupport::TestCase
end
test 'multi linked sample validation' do
- patient = FactoryBot.create(:patient_sample)
- patient2 = FactoryBot.create(:patient_sample, sample_type:patient.sample_type )
+ patient = FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy))
+ patient2 = FactoryBot.create(:patient_sample, sample_type:patient.sample_type, policy:FactoryBot.create(:public_policy) )
multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [FactoryBot.create(:project).id])
multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type
multi_linked_sample_type.save!
@@ -1176,4 +1174,182 @@ class SampleTest < ActiveSupport::TestCase
end
+ test 'validation of single linked sample permissions' do
+ person_a = FactoryBot.create(:person)
+ person_b = FactoryBot.create(:person)
+
+ pub_patient1 = FactoryBot.create(:patient_sample, contributor: person_a, policy: FactoryBot.create(:public_policy))
+
+ patient_sample_type = pub_patient1.sample_type
+
+ priv_patient1 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:private_policy) )
+
+ priv_patient2 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:private_policy) )
+
+ linked_sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: [person_a.projects.first.id])
+ linked_sample_type.sample_attributes.last.linked_sample_type = patient_sample_type
+ linked_sample_type.save!
+
+ sample = Sample.new(sample_type: linked_sample_type,
+ data:{
+ "title": 'Multiple Samples',
+ "patient": priv_patient1.id.to_s
+ },
+ contributor: person_a,
+ project_ids: [person_a.projects.first.id],
+ policy: FactoryBot.create(:editing_public_policy)
+ )
+
+ # sanity check
+ User.with_current_user(person_a) do
+ assert pub_patient1.can_view?
+ assert priv_patient1.can_view?
+ assert priv_patient2.can_view?
+ assert sample.can_edit?
+ end
+ User.with_current_user(person_b) do
+ assert pub_patient1.can_view?
+ refute priv_patient1.can_view?
+ refute priv_patient2.can_view?
+ assert sample.can_edit?
+ end
+
+ # new sample
+ User.with_current_user(person_b) do
+ refute sample.valid?
+ end
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ assert sample.save!
+ end
+
+ # change title attribute
+ sample.set_attribute_value(:title, 'new title')
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ end
+ User.with_current_user(person_b) do
+ assert sample.valid?
+ end
+
+ #change to a public patient
+ sample.set_attribute_value(:patient, pub_patient1.id)
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ end
+ User.with_current_user(person_b) do
+ assert sample.valid?
+ end
+
+ # change to different private patient
+ sample.set_attribute_value(:patient, priv_patient2.id)
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ end
+ User.with_current_user(person_b) do
+ refute sample.valid?
+ end
+
+ # change to nil
+ sample.set_attribute_value(:patient, nil)
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ end
+ User.with_current_user(person_b) do
+ assert sample.valid?
+ end
+ end
+
+ test 'validation of multi linked sample permissions' do
+ person_a = FactoryBot.create(:person)
+ person_b = FactoryBot.create(:person)
+
+
+ pub_patient1 = FactoryBot.create(:patient_sample, contributor: person_a, policy: FactoryBot.create(:public_policy))
+
+ patient_sample_type = pub_patient1.sample_type
+ pub_patient2 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:public_policy))
+
+ priv_patient1 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:private_policy) )
+
+ priv_patient2 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:private_policy) )
+
+ multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [person_a.projects.first.id])
+ multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient_sample_type
+ multi_linked_sample_type.save!
+
+ sample = Sample.new(sample_type: multi_linked_sample_type,
+ data:{
+ "title": 'Multiple Samples',
+ "patient": [pub_patient1.id.to_s, priv_patient1.id.to_s]
+ },
+ contributor: person_a,
+ project_ids: [person_a.projects.first.id],
+ policy: FactoryBot.create(:editing_public_policy)
+ )
+
+ # sanity check
+ User.with_current_user(person_a) do
+ assert pub_patient1.can_view?
+ assert pub_patient2.can_view?
+ assert priv_patient1.can_view?
+ assert priv_patient2.can_view?
+ assert sample.can_edit?
+ end
+ User.with_current_user(person_b) do
+ assert pub_patient1.can_view?
+ assert pub_patient2.can_view?
+ refute priv_patient1.can_view?
+ refute priv_patient2.can_view?
+ assert sample.can_edit?
+ end
+
+ # new sample
+ User.with_current_user(person_b) do
+ refute sample.valid?
+ end
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ assert sample.save!
+ end
+
+ # add a private entry
+ sample.set_attribute_value(:patient, [pub_patient1.id.to_s, priv_patient1.id.to_s, priv_patient2.id.to_s])
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ end
+ User.with_current_user(person_b) do
+ refute sample.valid?
+ end
+
+ # add a public entry
+ sample.set_attribute_value(:patient, [pub_patient1.id.to_s, priv_patient1.id.to_s, pub_patient2.id.to_s])
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ end
+ User.with_current_user(person_b) do
+ assert sample.valid?
+ end
+
+ # replace with a public entry
+ sample.set_attribute_value(:patient, [pub_patient2.id.to_s])
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ end
+ User.with_current_user(person_b) do
+ assert sample.valid?
+ end
+
+ # replace with a private entry
+ sample.set_attribute_value(:patient, [priv_patient2.id.to_s])
+ User.with_current_user(person_a) do
+ assert sample.valid?
+ end
+ User.with_current_user(person_b) do
+ refute sample.valid?
+ end
+
+
+ end
+
end
diff --git a/test/unit/sample_type_test.rb b/test/unit/sample_type_test.rb
index 4d88f237e3..24c2fec2c5 100644
--- a/test/unit/sample_type_test.rb
+++ b/test/unit/sample_type_test.rb
@@ -994,6 +994,104 @@ def setup
refute sample_type.contributor_credited?
end
+ test 'validates changes against editing constraints' do
+ sample_type = FactoryBot.create(:linked_optional_sample_type, contributor: @person)
+ different_sample_type = FactoryBot.create(:simple_sample_type, contributor: @person)
+ patient_sample = nil
+ User.with_current_user(@person.user) do
+ attr = sample_type.sample_attributes.detect { |t| t.accessor_name == 'patient' }
+ patient_sample = FactoryBot.create(:patient_sample, sample_type: attr.linked_sample_type, contributor: @person)
+ sample_type.samples.create!(data: { title: 'Lib-4', patient: patient_sample.id }, sample_type: sample_type,
+ project_ids: @person.project_ids)
+ end
+
+ assert sample_type.valid?
+
+ # Adding attribute
+ sample_type.sample_attributes.build(title: 'test 123')
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:sample_attributes, 'cannot be added, new attributes are not allowed (test 123)')
+
+ sample_type.reload
+ assert sample_type.valid?
+
+ # Removing attribute (via nested attributes)
+ sample_type.sample_attributes_attributes = { id: sample_type.sample_attributes.last.id, _destroy: '1' }
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:sample_attributes, 'cannot be removed, there are existing samples using this attribute (patient)')
+
+ sample_type.reload
+ assert sample_type.valid?
+
+ # Changing attribute title
+ sample_type.sample_attributes.last.title = 'banana'
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:'sample_attributes.title', 'cannot be changed (patient)')
+
+ sample_type.reload
+ assert sample_type.valid?
+
+ # Changing "required" attribute
+ User.with_current_user(@person.user) do
+ sample_type.samples.create!(data: { title: 'Lib-5', patient: nil }, sample_type: sample_type,
+ project_ids: @person.project_ids)
+ end
+ sample_type.sample_attributes.last.required = true
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:'sample_attributes.required', 'cannot be changed (patient)')
+
+ sample_type.reload
+ assert sample_type.valid?
+
+ # Changing "title" attribute
+ sample_type.sample_attributes.last.is_title = true
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:'sample_attributes.is_title', 'cannot be changed (patient)')
+
+ sample_type.reload
+ assert sample_type.valid?
+
+ # Changing sample attribute type
+ sample_type.sample_attributes.last.sample_attribute_type = FactoryBot.create(:integer_sample_attribute_type)
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:'sample_attributes.sample_attribute_type', 'cannot be changed (patient)')
+
+ sample_type.reload
+ assert sample_type.valid?
+
+ # Changing linked sample type
+ attr = sample_type.sample_attributes.detect { |t| t.accessor_name == 'patient' }
+ attr.linked_sample_type = different_sample_type
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:'sample_attributes.linked_sample_type', 'cannot be changed (patient)')
+
+ sample_type.reload
+ assert sample_type.valid?
+
+ # Changing sample controlled vocab
+ sample_type = FactoryBot.create(:apples_controlled_vocab_sample_type, contributor: @person)
+ User.with_current_user(@person.user) do
+ sample_type.samples.create!(data: { apples: 'Bramley' }, sample_type: sample_type, project_ids: @person.project_ids)
+ end
+
+ assert sample_type.valid?
+ attr = sample_type.sample_attributes.detect { |t| t.accessor_name == 'apples' }
+ attr.sample_controlled_vocab = FactoryBot.create(:sample_controlled_vocab)
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:'sample_attributes.sample_controlled_vocab', 'cannot be changed (apples)')
+
+ sample_type.reload
+ assert sample_type.valid?
+
+ # Changing unit
+ sample_type = patient_sample.sample_type
+ assert sample_type.valid?
+ attr = sample_type.sample_attributes.detect { |t| t.accessor_name == 'weight' }
+ attr.unit = FactoryBot.create(:unit)
+ refute sample_type.valid?
+ assert sample_type.errors.added?(:'sample_attributes.unit', 'cannot be changed (weight)')
+ end
+
private
# sample type with 3 samples
diff --git a/test/unit/samples/base_types_test.rb b/test/unit/samples/base_types_test.rb
index 782fc181d2..60433368cc 100644
--- a/test/unit/samples/base_types_test.rb
+++ b/test/unit/samples/base_types_test.rb
@@ -2,7 +2,7 @@
class BaseTypeTest < ActiveSupport::TestCase
test 'all types' do
- assert_equal %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList LinkedCustomMetadata).sort,
+ assert_equal %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList LinkedCustomMetadata LinkedCustomMetadataMulti).sort,
Seek::Samples::BaseType::ALL_TYPES.sort
end
@@ -21,6 +21,7 @@ class BaseTypeTest < ActiveSupport::TestCase
assert_equal 'SeekDataFile',Seek::Samples::BaseType::SEEK_DATA_FILE
assert_equal 'CVList',Seek::Samples::BaseType::CV_LIST
assert_equal 'LinkedCustomMetadata',Seek::Samples::BaseType::LINKED_CUSTOM_METADATA
+ assert_equal 'LinkedCustomMetadataMulti',Seek::Samples::BaseType::LINKED_CUSTOM_METADATA_MULTI
end
test 'valid?' do
diff --git a/test/unit/samples/sample_type_editing_constraints_test.rb b/test/unit/samples/sample_type_editing_constraints_test.rb
index 14aecb4b0e..c18b8ef549 100644
--- a/test/unit/samples/sample_type_editing_constraints_test.rb
+++ b/test/unit/samples/sample_type_editing_constraints_test.rb
@@ -55,6 +55,29 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase
refute_nil attr
assert c.allow_type_change?(attr)
assert c.allow_type_change?(nil)
+
+ type = FactoryBot.create(:linked_optional_sample_type)
+ c = Seek::Samples::SampleTypeEditingConstraints.new(type)
+ assert c.allow_type_change?(:patient)
+ attr = c.sample_type.sample_attributes.detect { |t| t.accessor_name == 'patient' }
+ refute_nil attr
+ assert c.allow_type_change?(attr)
+ assert c.allow_type_change?(nil)
+
+ person = FactoryBot.create(:person)
+ User.with_current_user(person.user) do
+ type.samples.create!(data: { title: 'Lib-3', patient: nil }, sample_type: type, project_ids: person.project_ids)
+
+ assert Seek::Samples::SampleTypeEditingConstraints.new(type).allow_type_change?(:patient),
+ 'Should still allow type change because patient was blank'
+
+ patient_sample = FactoryBot.create(:patient_sample, sample_type: attr.linked_sample_type, contributor: person)
+ type.samples.create!(data: { title: 'Lib-4', patient: patient_sample.id }, sample_type: type,
+ project_ids: person.project_ids)
+
+ refute Seek::Samples::SampleTypeEditingConstraints.new(type).allow_type_change?(:patient),
+ 'Should not allow type change because a sample exists with a patient'
+ end
end
test 'allow_required?' do
diff --git a/test/unit/snapshot_test.rb b/test/unit/snapshot_test.rb
index c66bb093ff..363e224fa7 100644
--- a/test/unit/snapshot_test.rb
+++ b/test/unit/snapshot_test.rb
@@ -10,14 +10,14 @@ class SnapshotTest < ActiveSupport::TestCase
contributor = FactoryBot.create(:person)
User.current_user = contributor.user
- @investigation = FactoryBot.create(:investigation, title: 'i1', description: 'not blank',
- policy: FactoryBot.create(:downloadable_public_policy), contributor:contributor)
+ @investigation = FactoryBot.create(:investigation, title: 'i1', description: 'not blank', contributor: contributor,
+ policy: FactoryBot.create(:downloadable_public_policy), creators: [contributor])
@study = FactoryBot.create(:study, title: 's1', investigation: @investigation, contributor: @investigation.contributor,
- policy: FactoryBot.create(:downloadable_public_policy))
+ policy: FactoryBot.create(:downloadable_public_policy), creators: [contributor])
@assay = FactoryBot.create(:assay, title: 'a1', study: @study, contributor: @investigation.contributor,
- policy: FactoryBot.create(:downloadable_public_policy))
+ policy: FactoryBot.create(:downloadable_public_policy), creators: [contributor])
@assay2 = FactoryBot.create(:assay, title: 'a2', study: @study, contributor: @investigation.contributor,
- policy: FactoryBot.create(:downloadable_public_policy))
+ policy: FactoryBot.create(:downloadable_public_policy), creators: [contributor])
@data_file = FactoryBot.create(:data_file, title: 'df1', contributor: @investigation.contributor,
content_blob: FactoryBot.create(:doc_content_blob, original_filename: 'word.doc'),
policy: FactoryBot.create(:downloadable_public_policy))
diff --git a/test/unit/study_test.rb b/test/unit/study_test.rb
index d22ded3792..593a12b45e 100644
--- a/test/unit/study_test.rb
+++ b/test/unit/study_test.rb
@@ -45,6 +45,24 @@ class StudyTest < ActiveSupport::TestCase
assert !study.can_delete?(study.contributor)
end
+ # Users shouldn't be able to delete studies populated with samples through their linked sample types
+ test 'can only delete studies with empty sample types' do
+ study_source_sample_type = FactoryBot.create(:simple_sample_type, title: "Source Sample Type")
+ empty_sample_type = FactoryBot.create(:simple_sample_type, title: "Empty study Sample Type")
+ sources = (0..4).map do |i|
+ FactoryBot.create(:sample, title: "Source nr. #{i}", sample_type: study_source_sample_type)
+ end
+
+ study = FactoryBot.create(:study, title: "First study", sample_types: [study_source_sample_type])
+ empty_study = FactoryBot.create(:study, title: "Empty study", sample_types:[empty_sample_type])
+
+ assert_equal(study.sample_types.first.samples.size, 5)
+ assert(empty_study.sample_types.first.samples.none?)
+
+ assert_equal(study.state_allows_delete?, false)
+ assert_equal(empty_study.state_allows_delete?, true)
+ end
+
test 'publications through assays' do
assay1 = FactoryBot.create(:assay)
study = assay1.study
diff --git a/test/unit/workflow_test.rb b/test/unit/workflow_test.rb
index ef23488cf3..94480af0f6 100644
--- a/test/unit/workflow_test.rb
+++ b/test/unit/workflow_test.rb
@@ -148,7 +148,7 @@ class WorkflowTest < ActiveSupport::TestCase
end
test 'generates RO-Crate and gracefully handles diagram error for workflow/abstract workflow' do
- bad_generator = MiniTest::Mock.new
+ bad_generator = Minitest::Mock.new
def bad_generator.write_graph(struct)
raise 'oh dear'
end