diff --git a/.gitignore b/.gitignore
index e5eb8ea5bd..ab0ea98b5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ node_modules
/config/credentials/test.key
/config/credentials/staging.key
/config/credentials/production.key
+/config/credentials/appliance.key
/app/assets/builds/*
!/app/assets/builds/.keep
diff --git a/Gemfile b/Gemfile
index 710616a597..c423cef31f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -53,12 +53,11 @@ gem 'graphql', '~> 2.0.27'
gem 'graphql-client'
gem 'haml', '~> 5.1'
gem 'i18n'
-gem 'iconv'
gem 'iso-639', '~> 0.3.6'
gem 'multi_json'
gem 'mysql2', '0.5.5'
gem 'oj'
-gem 'ontologies_api_client', github: 'ncbo/ontologies_api_ruby_client', tag: 'v2.2.5'
+gem 'ontologies_api_client', github: 'ncbo/ontologies_api_ruby_client', tag: 'v2.4.0'
gem 'open_uri_redirections'
gem 'pry'
gem 'psych', '< 4'
@@ -69,9 +68,16 @@ gem 'recaptcha', '~> 5.9.0'
gem 'rest-client'
gem 'rexml', '~> 3'
gem 'stackprof', require: false
+
+# pinning strscan to v 3.0.1 to deal with deployment issue. Remove line below when issue is fixed
+gem 'strscan', '3.0.1'
+
gem 'terser'
gem 'thin'
gem 'will_paginate', '~> 3.0'
+gem 'net-ftp'
+gem 'flag-icons-rails', '~> 3.4'
+gem 'inline_svg'
group :staging, :production do
# Application monitoring
diff --git a/Gemfile.lock b/Gemfile.lock
index e8efaa91ba..4103dea808 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,9 +1,9 @@
GIT
remote: https://github.com/ncbo/ontologies_api_ruby_client.git
- revision: 115cf36f54f73eb10c503147f54bb6f6672d3d99
- tag: v2.2.5
+ revision: f589b13dfbbc133ea67cbae1a8f92b41ea85c14b
+ tag: v2.4.0
specs:
- ontologies_api_client (2.2.5)
+ ontologies_api_client (2.4.0)
activesupport (= 7.0.8)
addressable (~> 2.8)
excon
@@ -13,7 +13,6 @@ GIT
lz4-ruby
multi_json
oj
- spawnling (= 2.1.5)
GEM
remote: https://rubygems.org/
@@ -83,29 +82,33 @@ GEM
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
- addressable (2.8.5)
- public_suffix (>= 2.0.2, < 6.0)
- airbrussh (1.5.0)
+ addressable (2.8.7)
+ public_suffix (>= 2.0.2, < 7.0)
+ airbrussh (1.5.3)
sshkit (>= 1.6.1, != 1.7.0)
ast (2.4.2)
- autoprefixer-rails (10.4.16.0)
+ autoprefixer-rails (10.4.19.0)
execjs (~> 2)
base64 (0.1.0)
- bcrypt_pbkdf (1.1.0)
- bootsnap (1.17.1)
+ bcrypt_pbkdf (1.1.1)
+ bcrypt_pbkdf (1.1.1-arm64-darwin)
+ bcrypt_pbkdf (1.1.1-x86_64-darwin)
+ bigdecimal (3.1.8)
+ bootsnap (1.18.4)
msgpack (~> 1.2)
bootstrap (5.2.3)
autoprefixer-rails (>= 9.1.0)
popper_js (>= 2.11.6, < 3)
sassc-rails (>= 2.0.0)
- brakeman (6.0.1)
- builder (3.2.4)
- capistrano (3.18.0)
+ brakeman (6.2.1)
+ racc
+ builder (3.3.0)
+ capistrano (3.19.1)
airbrussh (>= 1.0.0)
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
- capistrano-bundler (2.1.0)
+ capistrano-bundler (2.1.1)
capistrano (~> 3.1)
capistrano-locally (0.3.0)
capistrano (~> 3.0)
@@ -119,11 +122,11 @@ GEM
sshkit (~> 1.3)
capistrano-yarn (2.0.2)
capistrano (~> 3.0)
- capybara (3.39.2)
+ capybara (3.40.0)
addressable
matrix
mini_mime (>= 0.1.3)
- nokogiri (~> 1.8)
+ nokogiri (~> 1.11)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
@@ -131,41 +134,47 @@ GEM
chart-js-rails (0.1.7)
railties (> 3.1)
coderay (1.1.3)
- concurrent-ruby (1.2.3)
+ concurrent-ruby (1.3.4)
crass (1.0.6)
cube-ruby (0.0.3)
daemons (1.4.1)
- dalli (3.2.6)
+ dalli (3.2.8)
date (3.3.4)
- debug (1.9.1)
+ debug (1.9.2)
irb (~> 1.10)
reline (>= 0.3.8)
- diff-lcs (1.5.0)
- domain_name (0.6.20231109)
+ diff-lcs (1.5.1)
+ domain_name (0.6.20240107)
ed25519 (1.3.0)
- erubi (1.12.0)
+ erubi (1.13.0)
erubis (2.7.0)
eventmachine (1.2.7)
- excon (0.108.0)
+ excon (0.111.0)
execjs (2.9.1)
- faraday (2.7.12)
- base64
- faraday-net_http (>= 2.0, < 3.1)
- ruby2_keywords (>= 0.0.4)
- faraday-excon (2.1.0)
- excon (>= 0.27.4)
- faraday (~> 2.0)
+ faraday (2.12.0)
+ faraday-net_http (>= 2.0, < 3.4)
+ json
+ logger
+ faraday-excon (2.2.0)
+ excon (>= 0.109.0)
+ faraday (>= 2.11.0, < 3)
faraday-multipart (1.0.4)
multipart-post (~> 2)
- faraday-net_http (3.0.2)
- ffi (1.16.3)
+ faraday-net_http (3.3.0)
+ net-http
+ ffi (1.17.0)
+ ffi (1.17.0-arm64-darwin)
+ ffi (1.17.0-x86_64-darwin)
+ flag-icons-rails (3.4.6.1)
+ sass-rails
flamegraph (0.9.5)
globalid (1.2.1)
activesupport (>= 6.1)
- graphql (2.0.27)
- graphql-client (0.18.0)
+ graphql (2.0.31)
+ base64
+ graphql-client (0.23.0)
activesupport (>= 3.0)
- graphql
+ graphql (>= 1.13.0)
haml (5.2.2)
temple (>= 0.8.0)
tilt
@@ -175,29 +184,32 @@ GEM
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
http-accept (1.7.0)
- http-cookie (1.0.5)
+ http-cookie (1.0.7)
domain_name (~> 0.5)
- i18n (1.14.1)
+ i18n (1.14.6)
concurrent-ruby (~> 1.0)
- iconv (1.0.8)
+ inline_svg (1.10.0)
+ activesupport (>= 3.0)
+ nokogiri (>= 1.6)
io-console (0.7.2)
- irb (1.12.0)
- rdoc
+ irb (1.14.0)
+ rdoc (>= 4.0.0)
reline (>= 0.4.2)
iso-639 (0.3.6)
jquery-rails (4.6.0)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
- jquery-ui-rails (6.0.1)
+ jquery-ui-rails (7.0.0)
railties (>= 3.2.16)
- jsbundling-rails (1.3.0)
+ jsbundling-rails (1.3.1)
railties (>= 6.0.0)
json (2.7.2)
language_server-protocol (3.17.0.3)
- listen (3.8.0)
+ listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
+ logger (1.6.1)
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
@@ -207,19 +219,24 @@ GEM
net-imap
net-pop
net-smtp
- marcel (1.0.2)
+ marcel (1.0.4)
matrix (0.4.2)
- method_source (1.0.0)
- mime-types (3.5.1)
+ method_source (1.1.0)
+ mime-types (3.5.2)
mime-types-data (~> 3.2015)
- mime-types-data (3.2023.1003)
+ mime-types-data (3.2024.0903)
mini_mime (1.1.5)
- minitest (5.21.2)
+ minitest (5.25.1)
msgpack (1.7.2)
multi_json (1.15.0)
- multipart-post (2.3.0)
+ multipart-post (2.4.1)
mysql2 (0.5.5)
- net-imap (0.4.7)
+ net-ftp (0.3.7)
+ net-protocol
+ time
+ net-http (0.4.1)
+ uri
+ net-imap (0.4.16)
date
net-protocol
net-pop (0.1.2)
@@ -228,23 +245,27 @@ GEM
timeout
net-scp (4.0.0)
net-ssh (>= 2.6.5, < 8.0.0)
- net-smtp (0.4.0)
+ net-sftp (4.0.0)
+ net-ssh (>= 5.0.0, < 8.0.0)
+ net-smtp (0.5.0)
net-protocol
- net-ssh (7.2.0)
+ net-ssh (7.2.3)
netrc (0.11.0)
- newrelic_rpm (9.6.0)
- base64
- nio4r (2.6.1)
- nokogiri (1.16.0-arm64-darwin)
+ newrelic_rpm (9.13.0)
+ nio4r (2.7.3)
+ nokogiri (1.16.7-arm64-darwin)
racc (~> 1.4)
- nokogiri (1.16.0-x86_64-darwin)
+ nokogiri (1.16.7-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.16.0-x86_64-linux)
+ nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
- oj (3.16.1)
+ oj (3.16.6)
+ bigdecimal (>= 3.0)
+ ostruct (>= 0.2)
open_uri_redirections (0.2.1)
- parallel (1.24.0)
- parser (3.3.0.5)
+ ostruct (0.6.0)
+ parallel (1.26.3)
+ parser (3.3.5.0)
ast (~> 2.4.1)
racc
popper_js (2.11.8)
@@ -252,10 +273,10 @@ GEM
coderay (~> 1.1)
method_source (~> 1.0)
psych (3.3.4)
- public_suffix (5.0.4)
- racc (1.7.3)
- rack (2.2.8)
- rack-mini-profiler (3.1.1)
+ public_suffix (6.0.1)
+ racc (1.8.1)
+ rack (2.2.9)
+ rack-mini-profiler (3.3.1)
rack (>= 1.2.0)
rack-test (2.1.0)
rack (>= 1.3)
@@ -294,55 +315,56 @@ GEM
rainbow (3.1.1)
rake (13.2.1)
rb-fsevent (0.11.2)
- rb-inotify (0.10.1)
+ rb-inotify (0.11.1)
ffi (~> 1.0)
rdoc (6.3.4.1)
recaptcha (5.9.0)
json
redis (4.8.1)
- regexp_parser (2.9.0)
- reline (0.5.0)
+ regexp_parser (2.9.2)
+ reline (0.5.10)
io-console (~> 0.5)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
- rexml (3.2.6)
- rspec-core (3.12.2)
- rspec-support (~> 3.12.0)
- rspec-expectations (3.12.3)
+ rexml (3.3.7)
+ rspec-core (3.13.1)
+ rspec-support (~> 3.13.0)
+ rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.12.0)
- rspec-mocks (3.12.6)
+ rspec-support (~> 3.13.0)
+ rspec-mocks (3.13.1)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.12.0)
- rspec-rails (6.1.0)
- actionpack (>= 6.1)
- activesupport (>= 6.1)
- railties (>= 6.1)
- rspec-core (~> 3.12)
- rspec-expectations (~> 3.12)
- rspec-mocks (~> 3.12)
- rspec-support (~> 3.12)
- rspec-support (3.12.1)
- rubocop (1.63.3)
+ rspec-support (~> 3.13.0)
+ rspec-rails (7.0.1)
+ actionpack (>= 7.0)
+ activesupport (>= 7.0)
+ railties (>= 7.0)
+ rspec-core (~> 3.13)
+ rspec-expectations (~> 3.13)
+ rspec-mocks (~> 3.13)
+ rspec-support (~> 3.13)
+ rspec-support (3.13.1)
+ rubocop (1.66.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
- regexp_parser (>= 1.8, < 3.0)
- rexml (>= 3.2.5, < 4.0)
- rubocop-ast (>= 1.31.1, < 2.0)
+ regexp_parser (>= 2.4, < 3.0)
+ rubocop-ast (>= 1.32.2, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
- rubocop-ast (1.31.2)
- parser (>= 3.3.0.4)
+ rubocop-ast (1.32.3)
+ parser (>= 3.3.1.0)
ruby-progressbar (1.13.0)
- ruby2_keywords (0.0.5)
- ruby_parser (3.20.3)
+ ruby_parser (3.21.1)
+ racc (~> 1.5)
sexp_processor (~> 4.16)
+ sass-rails (6.0.0)
+ sassc-rails (~> 2.1, >= 2.1.1)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
@@ -352,48 +374,54 @@ GEM
sprockets-rails
tilt
select2-rails (4.0.13)
- sexp_processor (4.17.0)
- spawnling (2.1.5)
+ sexp_processor (4.17.2)
sprockets (4.2.1)
concurrent-ruby (~> 1.0)
rack (>= 2.2.4, < 4)
- sprockets-rails (3.4.2)
- actionpack (>= 5.2)
- activesupport (>= 5.2)
+ sprockets-rails (3.5.2)
+ actionpack (>= 6.1)
+ activesupport (>= 6.1)
sprockets (>= 3.0.0)
- sshkit (1.21.6)
+ sshkit (1.23.1)
+ base64
net-scp (>= 1.1.2)
+ net-sftp (>= 2.1.2)
net-ssh (>= 2.8.0)
- stackprof (0.2.25)
- stimulus-rails (1.3.3)
+ ostruct
+ stackprof (0.2.26)
+ stimulus-rails (1.3.4)
railties (>= 6.0.0)
+ strscan (3.0.1)
temple (0.10.3)
- terser (1.1.20)
+ terser (1.2.3)
execjs (>= 0.3.0, < 3)
thin (1.8.2)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
- thor (1.3.0)
- tilt (2.3.0)
+ thor (1.3.2)
+ tilt (2.4.0)
+ time (0.4.0)
+ date
timeout (0.4.1)
- turbo-rails (1.5.0)
+ turbo-rails (2.0.9)
actionpack (>= 6.0.0)
- activejob (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
- unicode-display_width (2.5.0)
+ unicode-display_width (2.6.0)
+ uri (0.13.1)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
will_paginate (3.3.1)
xpath (3.2.0)
nokogiri (~> 1.8)
- zeitwerk (2.6.12)
+ zeitwerk (2.6.18)
PLATFORMS
arm64-darwin-22
+ arm64-darwin-23
x86_64-darwin-21
x86_64-linux
@@ -416,13 +444,14 @@ DEPENDENCIES
dalli
debug
ed25519 (>= 1.2, < 2.0)
+ flag-icons-rails (~> 3.4)
flamegraph
graphql (~> 2.0.27)
graphql-client
haml (~> 5.1)
html2haml
i18n
- iconv
+ inline_svg
iso-639 (~> 0.3.6)
jquery-rails
jquery-ui-rails
@@ -430,6 +459,7 @@ DEPENDENCIES
listen
multi_json
mysql2 (= 0.5.5)
+ net-ftp
newrelic_rpm
oj
ontologies_api_client!
@@ -451,6 +481,7 @@ DEPENDENCIES
sprockets-rails
stackprof
stimulus-rails
+ strscan (= 3.0.1)
terser
thin
turbo-rails
@@ -458,4 +489,4 @@ DEPENDENCIES
will_paginate (~> 3.0)
BUNDLED WITH
- 2.4.19
+ 2.5.11
diff --git a/app/assets/javascripts/bp_class_tree.js.erb b/app/assets/javascripts/bp_class_tree.js.erb
index e3cbbc8c95..74c7e9f622 100644
--- a/app/assets/javascripts/bp_class_tree.js.erb
+++ b/app/assets/javascripts/bp_class_tree.js.erb
@@ -86,7 +86,7 @@ function initClassTree() {
});
};
-function nodeClicked(node_id) {
+function nodeClicked(node_id, lang = "en") {
// Get current html and store data in cache (to account for changes since the cache was retrieved)
setCacheCurrent();
@@ -128,12 +128,12 @@ function nodeClicked(node_id) {
// Insert notes table
insertNotesTable(tabData["notes_table_data"]);
-
wrapupTabChange(selectedTab);
} else {
jQuery.blockUI({ message: '
' + '<%= image_tag src="jquery.simple.tree/spinner.gif" %>' + ' Loading Class...
', showOverlay: false });
- jQuery.get('/ajax_concepts/'+jQuery(document).data().bp.ont_viewer.ontology_id+'/?conceptid='+node_id+'&callback=load',
- function(data){
+ var ajaxUrl = '/ajax_concepts/'+jQuery(document).data().bp.ont_viewer.ontology_id+'/?conceptid='+node_id+'&lang=' + lang + '&callback=load'
+ jQuery.get(ajaxUrl,
+ function(data) {
var tabData = data.split("|||");
// the tabs
@@ -181,14 +181,16 @@ function placeTreeView(treeHTML) {
}
// Retrieve the tree view using ajax
-function getTreeView() {
+function getTreeView(lang = "en") {
+ var url = "/ajax/classes/treeview?ontology="+jQuery(document).data().bp.ont_viewer.ontology_id+"&lang=" + lang + "&conceptid="+encodeURIComponent(jQuery(document).data().bp.ont_viewer.concept_id);
jQuery.ajax({
- url: "/ajax/classes/treeview?ontology="+jQuery(document).data().bp.ont_viewer.ontology_id+"&conceptid="+encodeURIComponent(jQuery(document).data().bp.ont_viewer.concept_id),
+ url: url,
success: function(data) {
placeTreeView(data);
},
error: function(data) {
- jQuery.get("/ajax/classes/treeview?ontology="+jQuery(document).data().bp.ont_viewer.ontology_id+"&conceptid=root", function(data){
+ var url = "/ajax/classes/treeview?ontology="+jQuery(document).data().bp.ont_viewer.ontology_id+"&lang=" + lang + "&conceptid=root";
+ jQuery.get(url, function(data) {
var rootTree = "Displaying the path to this class has taken too long. You can browse classes below.
" + data;
placeTreeView(rootTree);
});
@@ -201,6 +203,7 @@ function getTreeView() {
// We do this right after writing #sd_content to the dom to make sure it loads before other async portions of the page
jQuery(document).ready(function(){
if (pageUsesTreeView()) {
- getTreeView();
+ var lang = jQuery(document).data().bp.ont_viewer.lang;
+ getTreeView(lang);
}
});
diff --git a/app/assets/javascripts/bp_ontology_viewer.js.erb b/app/assets/javascripts/bp_ontology_viewer.js.erb
index e595cf3c23..276cfa27d5 100644
--- a/app/assets/javascripts/bp_ontology_viewer.js.erb
+++ b/app/assets/javascripts/bp_ontology_viewer.js.erb
@@ -82,18 +82,16 @@ function displayTree(data) {
var metadata_only = jQuery(document).data().bp.ont_viewer.metadata_only;
var purl_prefix = jQuery(document).data().bp.ont_viewer.purl_prefix;
var concept_name_title = jQuery(document).data().bp.ont_viewer.concept_name_title;
+ var lang = jQuery(document).data().bp.ont_viewer.lang;
// Check to see if we're actually loading a new concept or just displaying the one we already loaded previously
if (typeof new_concept_id === 'undefined' || new_concept_id == concept_id) {
-
if (concept_id !== "") {
History.replaceState({p:"classes", conceptid:concept_id}, jQuery.bioportal.ont_pages["classes"].page_name + " | " + org_site, "?p=classes" + "&conceptid=" + concept_id);
}
jQuery.unblockUI();
return;
-
} else {
-
var new_concept_param = (typeof new_concept_id === 'undefined') ? "" : "&conceptid=" + new_concept_id;
if (typeof new_concept_id !== 'undefined') {
@@ -137,7 +135,7 @@ function displayTree(data) {
simpleTreeCollection.get(0).setTreeNodes(list);
// Simulate node click
- nodeClicked(data.conceptid);
+ nodeClicked(data.conceptid, lang);
// Make "clicked" node active
jQuery("a.active").removeClass("active");
@@ -146,7 +144,7 @@ function displayTree(data) {
// Clear the search box
jQuery("#search_box").val("");
} else {
- nodeClicked(data.conceptid);
+ nodeClicked(data.conceptid, lang);
// Clear the search box
jQuery("#search_box").val("");
@@ -161,7 +159,7 @@ function displayTree(data) {
if (document.getElementById(new_concept_id) !== null) {
// We have a visible node that's been clicked, get the details for that node
jQuery.bioportal.ont_pages["classes"].published = true;
- nodeClicked(new_concept_id);
+ nodeClicked(new_concept_id, lang);
} else {
// Get a new copy of the tree because our concept isn't visible
// This could be due to using the forward/back button
@@ -201,6 +199,12 @@ function showOntologyContent(content_section) {
// Instead, fire some history events
var nav_ont = function(link) {
var page = jQuery(link).attr("data-bp-ont-page");
+
+ if (jQuery(document).data().bp.ont_viewer.lang_sections.includes(page)) {
+ jQuery("#navbar-ontology li.lang-dropdown").show();
+ } else {
+ jQuery("#navbar-ontology li.lang-dropdown").hide();
+ }
History.pushState({p:page}, jQuery.bioportal.ont_pages[page].page_name + " | " + jQuery(document).data().bp.ont_viewer.org_site, "?p=" + page);
}
diff --git a/app/assets/javascripts/bp_visualize.js.erb b/app/assets/javascripts/bp_visualize.js.erb
index 0e4b255426..9fdcebe5b7 100644
--- a/app/assets/javascripts/bp_visualize.js.erb
+++ b/app/assets/javascripts/bp_visualize.js.erb
@@ -88,6 +88,10 @@
jQuery(document).trigger("visualize_tab_change", [{tabType: tabId}]);
}
+ function isNotEmpty(arr) {
+ return Array.isArray(arr) && arr.length > 0;
+ }
+
// Only show BioMixer when tab is clicked
jQuery(document).live("visualize_tab_change", function(event, data){
if (data.tabType == "visualization") {
@@ -97,8 +101,16 @@
jQuery(document).data().bp.classesTab.search_box_init = function(){
if (jQuery("#search_box").bioportal_autocomplete) {
+ let extraParams = {
+ objecttypes: 'class'
+ };
+
+ if (isNotEmpty(jQuery(document).data().bp.ont_viewer.submission_lang)) {
+ extraParams["lang"] = jQuery(document).data().bp.ont_viewer.lang;
+ }
+
jQuery("#search_box").bioportal_autocomplete("/search/json_search/"+jQuery(document).data().bp.ontology.acronym, {
- extraParams: { objecttypes: "class" },
+ extraParams: extraParams,
selectFirst: true,
lineSeparator: "~!~",
matchSubset: 0,
diff --git a/app/assets/stylesheets/account.scss b/app/assets/stylesheets/account.scss
new file mode 100644
index 0000000000..f371532d9f
--- /dev/null
+++ b/app/assets/stylesheets/account.scss
@@ -0,0 +1,53 @@
+.signup {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding-top: 40px;
+ padding-bottom: 40px;
+}
+
+.form-signup {
+ width: 100%;
+ max-width: 400px;
+ padding: 15px;
+ margin: 0 auto;
+
+ a {
+ text-decoration: none;
+ }
+
+ a:hover {
+ text-decoration: underline;
+ }
+
+ h4, p {
+ text-align: center;
+ }
+}
+
+.form-signup .enable-lists {
+ color: red;
+}
+
+.edit-user-info {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ form {
+ width: 100%;
+ max-width: 640px;
+ padding: 15px;
+ margin: 0 auto;
+ }
+}
+
+.account-info {
+ a {
+ text-decoration: none;
+ }
+
+ a:hover {
+ text-decoration: underline;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss
index 99eabc57e8..3647b07fa4 100644
--- a/app/assets/stylesheets/application.css.scss
+++ b/app/assets/stylesheets/application.css.scss
@@ -19,16 +19,19 @@
*= require thickbox
*= require select2
*= require trumbowyg
+ *= require flag-icon
*
*/
/* BioPortal */
@import "admin";
+@import "account";
@import "annotator";
@import "bioportal";
@import "concepts";
@import "footer";
@import "home";
+@import "login";
@import "mappings";
@import "notes";
@import "notice";
diff --git a/app/assets/stylesheets/login.scss b/app/assets/stylesheets/login.scss
new file mode 100644
index 0000000000..8a8db9b9c5
--- /dev/null
+++ b/app/assets/stylesheets/login.scss
@@ -0,0 +1,41 @@
+.signin {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding-top: 40px;
+ padding-bottom: 40px;
+}
+
+.form-signin {
+ width: 100%;
+ max-width: 400px;
+ padding: 15px;
+ margin: 0 auto;
+
+ a {
+ text-decoration: none;
+ }
+
+ a:hover {
+ text-decoration: underline;
+ }
+
+ h4, p {
+ text-align: center;
+ }
+}
+
+.form-signin .enable-lists {
+ color: red;
+}
+
+.password-reset {
+ display: flex;
+ justify-content: center;
+ padding-top: 40px;
+ padding-bottom: 40px;
+
+ form {
+ max-width: 640px;
+ }
+}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 488cbda5a1..06cd2e3024 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -243,7 +243,8 @@ def redirect_new_api(class_view = false)
not_found unless acronym
if class_view
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym).first
- concept = get_class(params).first.to_s
+ @submission = get_ontology_submission_ready(@ontology)
+ concept = get_class(params, @submission).first.to_s
redirect_to "/ontologies/#{acronym}?p=classes#{params_string_for_redirect(params, prefix: "&")}", :status => :moved_permanently
else
redirect_to "/ontologies/#{acronym}#{params_string_for_redirect(params)}", :status => :moved_permanently
@@ -349,10 +350,10 @@ def using_captcha?
ENV['USE_RECAPTCHA'].present? && ENV['USE_RECAPTCHA'] == 'true'
end
- def get_class(params)
+ def get_class(params, submission)
+ lang = helpers.request_lang(submission)
if @ontology.flat?
-
ignore_concept_param = params[:conceptid].nil? ||
params[:conceptid].empty? ||
params[:conceptid].eql?("root") ||
@@ -367,34 +368,37 @@ def get_class(params)
@concept.children = []
else
# Display only the requested class in the tree
- @concept = @ontology.explore.single_class({full: true}, params[:conceptid])
+ @concept = @ontology.explore.single_class({full: true, lang: lang}, params[:conceptid])
@concept.children = []
end
@root = LinkedData::Client::Models::Class.new
@root.children = [@concept]
-
else
-
# not ignoring 'bp_fake_root' here
ignore_concept_param = params[:conceptid].nil? ||
params[:conceptid].empty? ||
params[:conceptid].eql?("root")
+
if ignore_concept_param
# get the top level nodes for the root
# TODO_REV: Support views? Replace old view call: @ontology.top_level_classes(view)
- roots = @ontology.explore.roots
+ roots = @ontology.explore.roots(lang: lang)
+
if roots.nil? || roots.empty?
LOG.add :debug, "Missing roots for #{@ontology.acronym}"
not_found
end
@root = LinkedData::Client::Models::Class.new(read_only: true)
- @root.children = roots.sort{|x,y| (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase}
+ @root.children = roots.sort{|x,y|
+ x.prefLabel = helpers.link_last_part(x.id) if x.prefLabel.to_s.empty?
+ y.prefLabel = helpers.link_last_part(y.id) if y.prefLabel.to_s.empty?
+ (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase}
# get the initial concept to display
root_child = @root.children.first
+ @concept = root_child.explore.self(full: true, lang: lang)
- @concept = root_child.explore.self(full: true)
# Some ontologies have "too many children" at their root. These will not process and are handled here.
if @concept.nil?
LOG.add :debug, "Missing class #{root_child.links.self}"
@@ -402,20 +406,23 @@ def get_class(params)
end
else
# if the id is coming from a param, use that to get concept
- @concept = @ontology.explore.single_class({full: true}, params[:conceptid])
+ @concept = @ontology.explore.single_class({full: true, lang: lang}, params[:conceptid])
if @concept.nil? || @concept.errors
LOG.add :debug, "Missing class #{@ontology.acronym} / #{params[:conceptid]}"
not_found
end
# Create the tree
- rootNode = @concept.explore.tree(include: "prefLabel,hasChildren,obsolete")
+ rootNode = @concept.explore.tree(include: "prefLabel,hasChildren,obsolete", lang: lang)
+
if rootNode.nil? || rootNode.empty?
- roots = @ontology.explore.roots
+ roots = @ontology.explore.roots(lang: lang)
+
if roots.nil? || roots.empty?
LOG.add :debug, "Missing roots for #{@ontology.acronym}"
not_found
end
+
if roots.any? {|c| c.id == @concept.id}
rootNode = roots
else
@@ -423,10 +430,12 @@ def get_class(params)
end
end
@root = LinkedData::Client::Models::Class.new(read_only: true)
- @root.children = rootNode.sort{|x,y| (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase}
+ @root.children = rootNode.sort{|x,y|
+ x.prefLabel = helpers.link_last_part(x.id) if x.prefLabel.to_s.empty?
+ y.prefLabel = helpers.link_last_part(y.id) if y.prefLabel.to_s.empty?
+ (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase}
end
end
-
@concept
end
diff --git a/app/controllers/concepts_controller.rb b/app/controllers/concepts_controller.rb
index f518eed670..b945f04e60 100644
--- a/app/controllers/concepts_controller.rb
+++ b/app/controllers/concepts_controller.rb
@@ -16,13 +16,15 @@ def show
# find_by_acronym includes views by default
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
+ @submission = get_ontology_submission_ready(@ontology)
@ob_instructions = helpers.ontolobridge_instructions_template(@ontology)
if request.xhr?
display = params[:callback].eql?('load') ? { full: true } : { display: 'prefLabel' }
+ display[:language] = helpers.request_lang(@submission)
@concept = @ontology.explore.single_class(display, params[:id])
not_found if @concept.nil?
- show_ajax_request
+ show_ajax_request(@submission)
else
render plain: 'Non-AJAX requests are not accepted at this URL', status: :forbidden
end
@@ -53,7 +55,8 @@ def show_tree
if @ontology.nil?
not_found
else
- get_class(params)
+ @submission = get_ontology_submission_ready(@ontology)
+ get_class(params, @submission)
render partial: 'ontologies/treeview'
end
end
@@ -105,14 +108,18 @@ def redirect_new_api
# Load data for a concept or retrieve a concept's children, depending on the value of the :callback parameter.
# Children are retrieved for drawing ontology class trees.
- def show_ajax_request
+ def show_ajax_request(submission)
case params[:callback]
when 'load'
gather_details
render partial: 'load'
when 'children'
- @children = @concept.explore.children(pagesize: 750).collection || []
- @children.sort! { |x, y| (x.prefLabel || '').downcase <=> (y.prefLabel || '').downcase }
+ @children = @concept.explore.children(pagesize: 750, language: helpers.request_lang(submission)).collection || []
+ @children.sort! do |x, y|
+ x.prefLabel = helpers.link_last_part(x.id) if x.prefLabel.to_s.empty?
+ y.prefLabel = helpers.link_last_part(y.id) if y.prefLabel.to_s.empty?
+ (x.prefLabel || '').downcase <=> (y.prefLabel || '').downcase
+ end
render partial: 'child_nodes'
end
end
@@ -123,4 +130,5 @@ def gather_details
@delete_mapping_permission = check_delete_mapping_permission(@mappings)
update_tab(@ontology, @concept.id)
end
+
end
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index eca05fcba4..c0d98a519a 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -107,11 +107,15 @@ def account
@user_ontologies = @user.customOntology
@user_ontologies ||= []
- onts = LinkedData::Client::Models::Ontology.all
- @admin_ontologies = onts.select { |o| o.administeredBy.include? @user.id }
+ @admin_ontologies = LinkedData::Client::Models::Ontology.where do |o|
+ o.administeredBy.include? @user.id
+ end
+ @admin_ontologies.sort! { |a, b| a.name.downcase <=> b.name.downcase }
- projects = LinkedData::Client::Models::Project.all
- @user_projects = projects.select { |p| p.creator.include? @user.id }
+ @user_projects = LinkedData::Client::Models::Project.where do |p|
+ p.creator.include? @user.id
+ end
+ @user_projects.sort! { |a, b| a.name.downcase <=> b.name.downcase }
render 'users/show'
end
diff --git a/app/controllers/language_controller.rb b/app/controllers/language_controller.rb
new file mode 100644
index 0000000000..0ccf6b59c5
--- /dev/null
+++ b/app/controllers/language_controller.rb
@@ -0,0 +1,21 @@
+class LanguageController < ApplicationController
+
+ # set locale to the language selected by the user
+ def set_locale_language
+ language = params[:language].strip.downcase.to_sym
+ supported_languages = I18n.available_locales
+
+ if language
+ if supported_languages.include?(language)
+ cookies.permanent[:locale] = language
+ else
+ # in case we want to show a message if the language is not available
+ flash.now[:notice] = t('language.translation_not_available', language: language)
+ logger.error flash.now[:notice]
+ end
+ end
+
+ redirect_to request.referer || root_path
+ end
+
+end
diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb
index 2a9587268a..6c331fb199 100755
--- a/app/controllers/login_controller.rb
+++ b/app/controllers/login_controller.rb
@@ -1,5 +1,6 @@
-class LoginController < ApplicationController
+# frozen_string_literal: true
+class LoginController < ApplicationController
layout :determine_layout
def index
@@ -7,7 +8,7 @@ def index
if params[:redirect]
# Get the original, encoded redirect
uri = URI.parse(request.url)
- orig_params = Hash[uri.query.split("&").map {|e| e.split("=",2)}].symbolize_keys
+ orig_params = Hash[uri.query.split("&").map { |e| e.split("=", 2) }].symbolize_keys
session[:redirect] = orig_params[:redirect]
else
session[:redirect] = request.referer
@@ -17,31 +18,30 @@ def index
# logs in a user
def create
@errors = validate(params[:user])
- if @errors.size < 1
+ if @errors.empty?
logged_in_user = LinkedData::Client::Models::User.authenticate(params[:user][:username], params[:user][:password])
if logged_in_user && !logged_in_user.errors
login(logged_in_user)
- redirect = "/"
+ redirect = '/'
if session[:redirect]
redirect = CGI.unescape(session[:redirect])
end
-
redirect_to redirect
else
- @errors << "Invalid account name/password combination"
- render :action => 'index'
+ @errors << 'Invalid account name/password combination'
+ render 'index'
end
else
- render :action => 'index'
+ render 'index'
end
end
# Login as the provided username (only for admin users)
def login_as
unless session[:user] && session[:user].admin?
- redirect_to "/"
+ redirect_to '/'
return
end
@@ -54,8 +54,8 @@ def login_as
session[:user].apikey = session[:admin_user].apikey
end
- #redirect_to request.referer rescue redirect_to "/"
- redirect_to "/"
+ # redirect_to request.referer rescue redirect_to "/"
+ redirect_to '/'
end
# logs out a user
@@ -67,25 +67,24 @@ def destroy
flash[:success] = "Logged out #{old_user.username}, returned to #{session[:user].username}".html_safe
else
session[:user] = nil
- flash[:success] = "You have successfully logged out"
+ flash[:success] = 'You have successfully logged out'
end
- redirect_to request.referer || "/"
+ redirect_to request.referer || '/'
end
- def lost_password
- end
+ def lost_password; end
# Sends a new password to the user
def send_pass
username = params[:user][:account_name]
email = params[:user][:email]
- resp = LinkedData::Client::HTTP.post("/users/create_reset_password_token", {username: username, email: email})
+ resp = LinkedData::Client::HTTP.post('/users/create_reset_password_token', { username: username, email: email })
if resp.nil?
- redirect_to login_index_path, notice: "Please check your email for a message with reset instructions"
+ redirect_to login_index_path, notice: 'Please check your email for a message with reset instructions'
else
- flash[:notice] = resp.errors.first + ". Please try again."
- redirect_to "/lost_pass"
+ flash[:notice] = "#{resp.errors.first}. Please try again."
+ redirect_to '/lost_pass'
end
end
@@ -93,14 +92,13 @@ def reset_password
username = params[:un]
email = params[:em]
token = params[:tk]
- @user = LinkedData::Client::HTTP.post("/users/reset_password", {username: username, email: email, token: token})
+ @user = LinkedData::Client::HTTP.post('/users/reset_password', { username: username, email: email, token: token })
if @user.is_a?(LinkedData::Client::Models::User)
- @user.validate_password = true
login(@user)
- render "users/edit"
+ render 'passwords/edit'
else
- flash[:notice] = @user.errors.first + ". Please reset your password again."
- redirect_to "/lost_pass"
+ flash[:notice] = "#{@user.errors.first}. Please reset your password again."
+ redirect_to '/lost_pass'
end
end
@@ -108,6 +106,7 @@ def reset_password
def login(user)
return unless user
+
session[:user] = user
custom_ontologies_text = session[:user].customOntology && !session[:user].customOntology.empty? ? "The display is now based on your Custom Ontology Set." : ""
notice = "Welcome " + user.username.to_s + "! " + custom_ontologies_text
@@ -115,17 +114,15 @@ def login(user)
end
def validate(params)
- errors=[]
+ errors = []
- if params[:username].nil? || params[:username].length <1
- errors << "Please enter an account name"
+ if params[:username].empty?
+ errors << 'Please enter an account name'
end
- if params[:password].nil? || params[:password].length <1
- errors << "Please enter a password"
+ if params[:password].empty?
+ errors << 'Please enter a password'
end
- return errors
+ errors
end
-
-
end
diff --git a/app/controllers/ontologies_controller.rb b/app/controllers/ontologies_controller.rb
index d61b1bfa59..aa8fadeed4 100644
--- a/app/controllers/ontologies_controller.rb
+++ b/app/controllers/ontologies_controller.rb
@@ -132,14 +132,14 @@ def index
end
def classes
- get_class(params)
+ @submission = get_ontology_submission_ready(@ontology)
+ get_class(params, @submission)
if ["application/ld+json", "application/json"].include?(request.accept)
render plain: @concept.to_jsonld, content_type: request.accept and return
end
@current_purl = @concept.purl if Rails.configuration.settings.purl[:enabled]
- @submission = get_ontology_submission_ready(@ontology)
unless @concept.id == "bp_fake_root"
@notes = @concept.explore.notes
@@ -188,7 +188,7 @@ def create
def edit
# Note: find_by_acronym includes ontology views
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id], include: 'all').first
redirect_to_home unless session[:user] && @ontology.administeredBy.include?(session[:user].id) || session[:user].admin?
@categories = LinkedData::Client::Models::Category.all
@user_select_list = LinkedData::Client::Models::User.all.map {|u| [u.username, u.id]}
@@ -254,9 +254,9 @@ def show
end
# Note: find_by_acronym includes ontology views
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology], include: 'all').first
not_found if @ontology.nil?
-
+
# Handle the case where an ontology is converted to summary only.
# See: https://github.com/ncbo/bioportal_web_ui/issues/133.
if @ontology.summaryOnly && params[:p].present?
@@ -313,7 +313,7 @@ def show
end
def submit_success
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id], include: 'all').first
render 'submit_success'
end
@@ -345,9 +345,9 @@ def update
return
end
# Note: find_by_acronym includes ontology views
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology][:acronym] || params[:id]).first
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first
@ontology.update_from_params(ontology_params)
- error_response = @ontology.update
+ error_response = @ontology.update(cache_refresh_all: false)
if response_error?(error_response)
@categories = LinkedData::Client::Models::Category.all
@user_select_list = LinkedData::Client::Models::User.all.map {|u| [u.username, u.id]}
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
new file mode 100644
index 0000000000..d6127809da
--- /dev/null
+++ b/app/controllers/passwords_controller.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+class PasswordsController < ApplicationController
+ before_action :require_logged_in_user
+ before_action :set_user
+
+ layout :determine_layout
+
+ def edit; end
+
+ def update
+ if params[:password] != params[:password_confirmation]
+ flash.now[:warning] = 'New password and password confirmation do not match. Please try again.'
+ render 'edit'
+ return
+ end
+
+ response = @user.update(values: { password: params[:password] })
+ if response_error?(response)
+ @errors = response_errors(response)
+ render 'edit'
+ else
+ flash[:success] = 'Password successfully updated!'
+ redirect_to user_path(@user.username)
+ end
+ end
+
+ private
+
+ def password_params
+ p = params.permit(:password, :password_confirmation)
+ p.to_h
+ end
+
+ def require_logged_in_user
+ if session[:user].blank?
+ flash[:warning] = 'You must be logged in to access that page'
+ redirect_to login_index_path
+ end
+ end
+
+ def set_user
+ @user = session[:user]
+ end
+end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 7de8f345f7..973fa9f641 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -17,18 +17,11 @@ def index
end
def show
- projects = LinkedData::Client::Models::Project.find_by_acronym(params[:id])
- if projects.blank?
- flash.alert = "Project not found: #{params[:id]}"
- redirect_to projects_path
- return
- end
-
- @project = projects.first
+ @project = LinkedData::Client::Models::Project.get(params[:id])
@ontologies_used = []
onts_used = @project.ontologyUsed
onts_used.each do |ont_used|
- ont = LinkedData::Client::Models::Ontology.find(ont_used)
+ ont = LinkedData::Client::Models::Ontology.get(ont_used, include: 'name,acronym')
@ontologies_used << Hash['name', ont.name, 'acronym', ont.acronym] unless ont.nil?
end
@ontologies_used.sort_by! { |o| o['name'].downcase }
@@ -45,13 +38,7 @@ def new
end
def edit
- projects = LinkedData::Client::Models::Project.find_by_acronym(params[:id])
- if projects.blank?
- flash.alert = "Project not found: #{params[:id]}"
- redirect_to projects_path
- return
- end
- @project = projects.first
+ @project = LinkedData::Client::Models::Project.get(params[:id])
@user_select_list = LinkedData::Client::Models::User.all.map { |u| [u.username, u.id] }
@user_select_list.sort! { |a, b| a[1].downcase <=> b[1].downcase }
@usedOntologies = @project.ontologyUsed || []
@@ -84,21 +71,15 @@ def create
end
def update
- projects = LinkedData::Client::Models::Project.find_by_acronym(params[:id])
- if projects.blank?
- flash.alert = "Project not found: #{params[:id]}"
- redirect_to projects_path
- return
- end
- @project = projects.first
+ @project = LinkedData::Client::Models::Project.get(params[:id])
@project.update_from_params(project_params)
- @user_select_list = LinkedData::Client::Models::User.all.map { |u| [u.username, u.id] }
- @user_select_list.sort! { |a, b| a[1].downcase <=> b[1].downcase }
- @usedOntologies = @project.ontologyUsed || []
- @ontologies = LinkedData::Client::Models::Ontology.all
- error_response = @project.update
+ error_response = @project.update(cache_refresh_all: false)
if response_error?(error_response)
@errors = response_errors(error_response)
+ @user_select_list = LinkedData::Client::Models::User.all.map { |u| [u.username, u.id] }
+ @user_select_list.sort! { |a, b| a[1].downcase <=> b[1].downcase }
+ @usedOntologies = @project.ontologyUsed || []
+ @ontologies = LinkedData::Client::Models::Ontology.all
render :edit
else
flash[:notice] = 'Project successfully updated'
@@ -107,13 +88,7 @@ def update
end
def destroy
- projects = LinkedData::Client::Models::Project.find_by_acronym(params[:id])
- if projects.blank?
- flash.alert = "Project not found: #{params[:id]}"
- redirect_to projects_path
- return
- end
- @project = projects.first
+ @project = LinkedData::Client::Models::Project.get(params[:id])
error_response = @project.delete
if response_error?(error_response)
@errors = response_errors(error_response)
diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb
index 042c3e4365..9280fdfb6f 100644
--- a/app/controllers/submissions_controller.rb
+++ b/app/controllers/submissions_controller.rb
@@ -5,15 +5,8 @@ class SubmissionsController < ApplicationController
before_action :authorize_and_redirect, only: [:edit, :update, :create, :new]
def new
- begin
- # REVIEW: do we really need this double attempt to locate an ontology? I think find_by_acronym (below) should
- # be sufficient. It's not evident that we call the new method with a full URI anymore.
- @ontology = LinkedData::Client::Models::Ontology.get(CGI.unescape(params[:ontology_id]))
- rescue MultiJson::ParseError
- nil
- end
-
- @ontology ||= LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
+ # NOTE: find_by_acronym includes ontology views
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology_id]).first
@submission = @ontology.explore.latest_submission
@submission ||= LinkedData::Client::Models::OntologySubmission.new
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 4d769260db..cc65fc2408 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class UsersController < ApplicationController
before_action :unescape_id, only: [:edit, :show, :update]
before_action :verify_owner, only: [:edit, :show]
@@ -5,8 +7,6 @@ class UsersController < ApplicationController
layout :determine_layout
- # GET /users
- # GET /users.xml
def index
@users = LinkedData::Client::Models::User.all
respond_to do |format|
@@ -15,94 +15,71 @@ def index
end
end
- # GET /users/1
- # GET /users/1.xml
def show
- @user = if session[:user].admin? && params.has_key?(:id)
- LinkedData::Client::Models::User.find_by_username(params[:id]).first
- else
- LinkedData::Client::Models::User.find(session[:user].id)
- end
+ @user = LinkedData::Client::Models::User.get(params[:id], include: 'all')
@all_ontologies = LinkedData::Client::Models::Ontology.all(ignore_custom_ontologies: true)
@user_ontologies = @user.customOntology
- ## Copied from home controller , account action
- onts = LinkedData::Client::Models::Ontology.all;
- @admin_ontologies = onts.select {|o| o.administeredBy.include? @user.id }
+ # Copied from home controller, account action
+ @admin_ontologies = LinkedData::Client::Models::Ontology.where do |o|
+ o.administeredBy.include? @user.id
+ end
+ @admin_ontologies.sort! { |a, b| a.name.downcase <=> b.name.downcase }
- projects = LinkedData::Client::Models::Project.all;
- @user_projects = projects.select {|p| p.creator.include? @user.id }
+ @user_projects = LinkedData::Client::Models::Project.where do |p|
+ p.creator.include? @user.id
+ end
+ @user_projects.sort! { |a, b| a.name.downcase <=> b.name.downcase }
end
- # GET /users/new
def new
@user = LinkedData::Client::Models::User.new
end
- # GET /users/1;edit
def edit
- @user = LinkedData::Client::Models::User.find(params[:id])
- @user ||= LinkedData::Client::Models::User.find_by_username(params[:id]).first
-
- if (params[:password].eql?("true"))
- @user.validate_password = true
- end
+ @user = LinkedData::Client::Models::User.get(params[:id], include: 'all')
end
- # POST /users
- # POST /users.xml
def create
@errors = validate(user_params)
@user = LinkedData::Client::Models::User.new(values: user_params)
- if @errors.size < 1
+ if @errors.empty?
@user_saved = @user.save
if response_error?(@user_saved)
@errors = response_errors(@user_saved)
# @errors = {acronym: "Username already exists, please use another"} if @user_saved.status == 409
- render action: "new"
+ render 'new'
else
- # Attempt to register user to list
- if params[:user][:register_mail_list]
- Notifier.register_for_announce_list(@user.email).deliver rescue nil
- end
-
flash[:notice] = 'Account was successfully created'
session[:user] = LinkedData::Client::Models::User.authenticate(@user.username, @user.password)
- redirect_to_browse
+ redirect_to user_path(@user.username)
end
else
- render action: "new"
+ render 'new'
end
end
- # PUT /users/1
- # PUT /users/1.xml
def update
- @user = LinkedData::Client::Models::User.find(params[:id])
- @user = LinkedData::Client::Models::User.find_by_username(params[:id]).first if @user.nil?
- @errors = validate_update(user_params)
- if @errors.size < 1
-
- if params[:user][:password]
- error_response = @user.update(values: { password: params[:user][:password] })
- else
- user_roles = @user.role
+ @user = LinkedData::Client::Models::User.get(params[:id], include: 'all')
- if @user.admin? != (params[:user][:admin].to_i == 1)
- user_roles = update_role(@user)
- end
+ @errors = validate_update(user_params)
+ if @errors.empty?
+ user_roles = @user.role
- @user.update_from_params(user_params.merge!(role: user_roles))
- error_response = @user.update
+ if @user.admin? != (params[:user][:admin].to_i == 1)
+ user_roles = update_role(@user)
end
+ @user.update_from_params(user_params.merge!(role: user_roles))
+ error_response = @user.update(cache_refresh_all: false)
+
if response_error?(error_response)
@errors = response_errors(error_response)
# @errors = {acronym: "Username already exists, please use another"} if error_response.status == 409
- render action: "edit"
+ render 'edit'
else
- flash[:notice] = 'Account was successfully updated'
+ flash[:notice] = 'Account successfully updated!'
if session[:user].username == @user.username
session[:user].update_from_params(user_params)
@@ -110,19 +87,16 @@ def update
redirect_to user_path(@user.username)
end
else
- render action: "edit"
+ render 'edit'
end
end
- # DELETE /users/1
def destroy
- response = {errors: '', success: ''}
- @user = LinkedData::Client::Models::User.find(params[:id])
- @user = LinkedData::Client::Models::User.find_by_username(params[:id]).first if @user.nil?
- if(session[:user].admin?)
+ response = { errors: String.new(''), success: String.new('') }
+ @user = LinkedData::Client::Models::User.get(params[:id])
+ if session[:user].admin?
@user.delete
response[:success] << 'User deleted successfully '
-
else
response[:errors] << 'Not permitted '
end
@@ -131,24 +105,23 @@ def destroy
end
def custom_ontologies
- @user = LinkedData::Client::Models::User.find(params[:id])
- @user = LinkedData::Client::Models::User.find_by_username(params[:id]).first if @user.nil?
+ @user = LinkedData::Client::Models::User.get(params[:id])
custom_ontologies = params[:ontology] ? params[:ontology][:ontologyId] : []
custom_ontologies.reject!(&:blank?)
@user.update_from_params(customOntology: custom_ontologies)
- error_response = @user.update
+ response = @user.update
- if error_response
- flash[:notice] = 'Error saving Custom Ontologies, please try again'
- else
- updated_user = LinkedData::Client::Models::User.find(@user.id)
+ if response.success?
+ updated_user = LinkedData::Client::Models::User.get(@user.id, include: 'customOntology')
session[:user].update_from_params(customOntology: updated_user.customOntology)
flash[:notice] = if updated_user.customOntology.empty?
- 'Custom Ontologies were cleared'
+ 'Custom ontology set successfully cleared'
else
- 'Custom Ontologies were saved'
+ 'Custom ontology set successfully saved'
end
+ else
+ flash[:error] = 'Error saving custom ontology set. Please try again.'
end
redirect_to user_path(@user.username)
end
@@ -156,8 +129,8 @@ def custom_ontologies
private
def user_params
- p = params.require(:user).permit(:firstName, :lastName, :username, :email, :email_confirmation, :password,
- :password_confirmation, :register_mail_list, :admin)
+ p = params.require(:user).permit(:firstName, :lastName, :username, :email, :password, :password_confirmation,
+ :admin, :githubId, :orcidId)
p.to_h
end
@@ -167,53 +140,42 @@ def unescape_id
def verify_owner
return if current_user_admin?
+
if session[:user].nil? || (!session[:user].id.eql?(params[:id]) && !session[:user].username.eql?(params[:id]))
redirect_to controller: 'login', action: 'index', redirect: "/accounts/#{params[:id]}"
end
end
def get_ontology_list(ont_hash)
- return "" if ont_hash.nil?
+ return '' if ont_hash.nil?
+
ontologies = []
ont_hash.each do |ont, checked|
ontologies << ont if checked.to_i == 1
end
- ontologies.join(";")
+ ontologies.join(';')
end
def validate(params)
errors = []
- if params[:email].nil? || params[:email].length < 1 || !params[:email].match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i)
- errors << "Please enter an email address"
- end
- if !params[:email].eql?(params[:email_confirmation])
- errors << "Your Email and Email Confirmation do not match"
- end
- if params[:password].nil? || params[:password].length < 1
- errors << "Please enter a password"
- end
- if !params[:password].eql?(params[:password_confirmation])
- errors << "Your Password and Password Confirmation do not match"
+ if params[:email].length < 1 || !params[:email].match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i)
+ errors << 'invalid email address'
end
if using_captcha?
if !verify_recaptcha
- errors << "Please fill in the proper text from the supplied image"
+ errors << 'reCAPTCHA verification failed, please try again'
end
end
- return errors
+ errors
end
def validate_update(params)
errors = []
- if params[:email].nil? || params[:email].length < 1 || !params[:email].match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i)
- errors << "Please enter an email address"
- end
- if !params[:password].eql?(params[:password_confirmation])
- errors << "Your Password and Password Confirmation do not match"
+ if params[:email].length < 1 || !params[:email].match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i)
+ errors << 'invalid email address'
end
-
- return errors
+ errors
end
def update_role(user)
@@ -222,9 +184,9 @@ def update_role(user)
if session[:user].admin?
user_roles = user_roles.dup
if user.admin?
- user_roles.map!{ |role| role == "ADMINISTRATOR" ? "LIBRARIAN" : role}
+ user_roles.map! { |role| role == 'ADMINISTRATOR' ? 'LIBRARIAN' : role }
else
- user_roles.map!{ |role| role == "LIBRARIAN" ? "ADMINISTRATOR" : role}
+ user_roles.map! { |role| role == 'LIBRARIAN' ? 'ADMINISTRATOR' : role }
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 3948fe3a2b..12ec47cfe5 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,46 +1,27 @@
-# Methods added to this helper will be available to all templates in the application.
-
require 'uri'
require 'cgi'
require 'digest/sha1'
-require 'pry' # used in a rescue
module ApplicationHelper
-
def get_apikey
unless session[:user].nil?
- return session[:user].apikey
+ session[:user].apikey
else
- return LinkedData::Client.settings.apikey
- end
- end
-
- def isOwner?(id)
- unless session[:user].nil?
- if session[:user].admin?
- return true
- elsif session[:user].id.eql?(id)
- return true
- else
- return false
- end
+ LinkedData::Client.settings.apikey
end
end
def clean(string)
- string = string.gsub("\"",'\'')
- return string.gsub("\n",'')
+ string = string.gsub("\"", '\'')
+ string.gsub("\n", '')
end
def clean_id(string)
- new_string = string.gsub(":","").gsub("-","_").gsub(".","_")
- return new_string
+ string.gsub(':', '').gsub('-', '_').gsub('.', '_')
end
def get_username(user_id)
- user = LinkedData::Client::Models::User.find(user_id)
- username = user.nil? ? user_id : user.username
- username
+ user_id.split('/').last
end
def current_user_admin?
@@ -49,61 +30,44 @@ def current_user_admin?
def remove_owl_notation(string)
# TODO_REV: No OWL notation, but should we modify the IRI?
- return string
-
- unless string.nil?
- strings = string.split(":")
- if strings.size<2
- #return string.titleize
- return string
- else
- #return strings[1].titleize
- return strings[1]
- end
- end
+ string
end
- def draw_tree(root, id = nil, type = "Menu")
+ def draw_tree(root, id = nil, type = 'Menu', submission)
if id.nil?
id = root.children.first.id
end
# TODO: handle tree view for obsolete classes, e.g. 'http://purl.obolibrary.org/obo/GO_0030400'
- raw build_tree(root, "", id) # returns a string, representing nested list items
+ raw build_tree(root, '', id, submission) # returns a string, representing nested list items
end
- def build_tree(node, string, id)
- if node.children.nil? || node.children.length < 1
- return string # unchanged
+ def build_tree(node, string, id, submission)
+ if node.children.nil? || node.children.empty?
+ return string
end
- node.children.sort! {|a,b| (a.prefLabel || a.id).downcase <=> (b.prefLabel || b.id).downcase}
- for child in node.children
- if child.id.eql?(id)
- active_style="class='active'"
- else
- active_style = ""
- end
- if child.expanded?
- open = "class='open'"
- else
- open = ""
- end
+
+ node.children.sort! { |a, b| (a.prefLabel || a.id).downcase <=> (b.prefLabel || b.id).downcase }
+ node.children.each do |child|
+ active_style = child.id.eql?(id) ? "class='active'" : ''
+ open = child.expanded? ? "class='open'" : ''
# This fake root will be present at the root of "flat" ontologies, we need to keep the id intact
- li_id = child.id.eql?("bp_fake_root") ? "bp_fake_root" : short_uuid
+ li_id = child.id.eql?('bp_fake_root') ? 'bp_fake_root' : short_uuid
- if child.id.eql?("bp_fake_root")
+ if child.id.eql?('bp_fake_root')
string << "#{child.prefLabel}"
else
icons = child.relation_icon(node)
- string << " #{child.prefLabel({use_html: true})} #{icons}"
+ string << " #{child.prefLabel({use_html: true})} #{icons}"
+
if child.hasChildren && !child.expanded?
- string << ""
+ string << ""
elsif child.expanded?
- string << ""
- build_tree(child, string, id)
- string << "
"
+ string << ''
+ build_tree(child, string, id, submission)
+ string << '
'
end
- string << ""
+ string << ''
end
end
@@ -111,11 +75,11 @@ def build_tree(node, string, id)
end
def loading_spinner(padding = false, include_text = true)
- loading_text = include_text ? " loading..." : ""
+ loading_text = include_text ? ' loading...' : ''
if padding
- raw('' + image_tag("spinners/spinner_000000_16px.gif", style: "vertical-align: text-bottom;") + loading_text + '
')
+ raw('' + image_tag('spinners/spinner_000000_16px.gif', style: 'vertical-align: text-bottom;') + loading_text + '
')
else
- raw(image_tag("spinners/spinner_000000_16px.gif", style: "vertical-align: text-bottom;") + loading_text)
+ raw(image_tag('spinners/spinner_000000_16px.gif', style: 'vertical-align: text-bottom;') + loading_text)
end
end
@@ -125,30 +89,11 @@ def short_uuid
rand(36**8).to_s(36)
end
- def help_icon(link, html_attribs = {})
- html_attribs["title"] ||= "Help"
- attribs = []
- html_attribs.each {|k,v| attribs << "#{k.to_s}='#{v}'"}
- return <<-BLOCK
-
-
-
- BLOCK
- end
-
- def anonymous_user
- #
- # TODO: Fix and failures from removing 'DataAccess' call here.
- #
- #user = DataAccess.getUser($ANONYMOUS_USER)
- user ||= User.new({"id" => 0})
- end
-
def render_advanced_picker(custom_ontologies = nil, selected_ontologies = [], align_to_dom_id = nil)
selected_ontologies ||= []
init_ontology_picker(custom_ontologies, selected_ontologies)
- render :partial => "shared/ontology_picker_advanced", :locals => {
- :custom_ontologies => custom_ontologies, :selected_ontologies => selected_ontologies, :align_to_dom_id => align_to_dom_id
+ render partial: 'shared/ontology_picker_advanced', locals: {
+ custom_ontologies: custom_ontologies, selected_ontologies: selected_ontologies, align_to_dom_id: align_to_dom_id
}
end
@@ -167,93 +112,86 @@ def init_ontology_picker_single
end
def get_ontologies_data(ontologies = nil)
- ontologies ||= LinkedData::Client::Models::Ontology.all(include: "acronym,name")
+ ontologies ||= LinkedData::Client::Models::Ontology.all(include: 'acronym,name')
@onts_for_select = []
@onts_acronym_map = {}
@onts_uri2acronym_map = {}
ontologies.each do |ont|
- # TODO: ontologies parameter may be a list of ontology models (not ontology submission models):
- # ont.acronym instead of ont.ontology.acronym
- # ont.name instead of ont.ontology.name
- # ont.id instead of ont.ontology.id
- # TODO: annotator passes in 'custom_ontologies' to the ontologies parameter.
- next if ( ont.acronym.nil? or ont.acronym.empty? )
+ next if ont.acronym.blank?
+
acronym = ont.acronym
name = ont.name
- #id = ont.id # ontology URI
- abbreviation = acronym.empty? ? "" : "(#{acronym})"
+ abbreviation = acronym.empty? ? '' : "(#{acronym})"
ont_label = "#{name.strip} #{abbreviation}"
- #@onts_for_select << [ont_label, id] # using the URI crashes the UI checkbox selection behavior.
@onts_for_select << [ont_label, acronym]
@onts_acronym_map[ont_label] = acronym
- @onts_uri2acronym_map[ont.id] = acronym # required in ontologies_to_acronyms
+ @onts_uri2acronym_map[ont.id] = acronym
end
- @onts_for_select.sort! { |a,b| a[0].downcase <=> b[0].downcase }
+ @onts_for_select.sort! { |a, b| a[0].downcase <=> b[0].downcase }
@onts_for_js = @onts_acronym_map.to_json
end
def categories_for_select
- # This method is called in the search index page.
get_ontologies_data
get_categories_data
- return @categories_for_select
+ @categories_for_select
end
def get_categories_data
@categories_for_select = []
@categories_map = {}
- categories = LinkedData::Client::Models::Category.all(include: "name,ontologies")
+ categories = LinkedData::Client::Models::Category.all(include: 'name,ontologies')
categories.each do |c|
- @categories_for_select << [ c.name, c.id ]
- @categories_map[c.id] = ontologies_to_acronyms(c.ontologies) # c.ontologies is a list of URIs
+ @categories_for_select << [c.name, c.id]
+ @categories_map[c.id] = ontologies_to_acronyms(c.ontologies)
end
- @categories_for_select.sort! { |a,b| a[0].downcase <=> b[0].downcase }
+ @categories_for_select.sort! { |a, b| a[0].downcase <=> b[0].downcase }
@categories_for_js = @categories_map.to_json
end
def get_groups_data
@groups_map = {}
@groups_for_select = []
- groups = LinkedData::Client::Models::Group.all(include: "acronym,name,ontologies")
+ groups = LinkedData::Client::Models::Group.all(include: 'acronym,name,ontologies')
groups.each do |g|
- next if ( g.acronym.nil? or g.acronym.empty? )
- @groups_for_select << [ g.name + " (#{g.acronym})", g.acronym ]
- @groups_map[g.acronym] = ontologies_to_acronyms(g.ontologies) # g.ontologies is a list of URIs
+ next if g.acronym.blank?
+
+ @groups_for_select << [g.name + " (#{g.acronym})", g.acronym]
+ @groups_map[g.acronym] = ontologies_to_acronyms(g.ontologies)
end
- @groups_for_select.sort! { |a,b| a[0].downcase <=> b[0].downcase }
+ @groups_for_select.sort! { |a, b| a[0].downcase <=> b[0].downcase }
@groups_for_js = @groups_map.to_json
end
def ontologies_to_acronyms(ontologyIDs)
acronyms = []
ontologyIDs.each do |id|
- acronyms << @onts_uri2acronym_map[id] # hash generated in get_ontologies_data
+ acronyms << @onts_uri2acronym_map[id]
end
- return acronyms.compact # remove nil values from any failures to convert ontology URI to acronym
+ acronyms.compact
end
def at_slice?
!@subdomain_filter.nil? && !@subdomain_filter[:active].nil? && @subdomain_filter[:active] == true
end
- def truncate_with_more(text, options = {})
- length ||= options[:length] ||= 30
- trailing_text ||= options[:trailing_text] ||= " ... "
- link_more ||= options[:link_more] ||= "[more]"
- link_less ||= options[:link_less] ||= "[less]"
- more_text = " #{link_more}#{text} #{link_less}"
- more = text.length > length ? more_text : ""
- output = "#{truncate(text, :length => length, :omission => trailing_text)}" + more + ""
+ def link_last_part(url)
+ return '' if url.nil?
+
+ if url.include?('#')
+ url.split('#').last
+ else
+ url.split('/').last
+ end
end
def subscribe_ontology_button(ontology_id, user = nil)
user = session[:user] if user.nil?
if user.nil?
- # subscribe button must redirect to login
return sanitize("Subscribe")
end
- # Init subscribe button parameters.
- sub_text = "Subscribe"
+
+ sub_text = 'Subscribe'
params = "data-bp_ontology_id='#{ontology_id}' data-bp_is_subbed='false' data-bp_user_id='#{user.id}'"
begin
# Try to create an intelligent subscribe button.
@@ -262,17 +200,15 @@ def subscribe_ontology_button(ontology_id, user = nil)
else
ont = LinkedData::Client::Models::Ontology.find_by_acronym(ontology_id).first
end
- subscribed = subscribed_to_ontology?(ont.acronym, user) # application_helper
- sub_text = subscribed ? "Unsubscribe" : "Subscribe"
+ subscribed = subscribed_to_ontology?(ont.acronym, user)
+ sub_text = subscribed ? 'Unsubscribe' : 'Subscribe'
params = "data-bp_ontology_id='#{ont.acronym}' data-bp_is_subbed='#{subscribed}' data-bp_user_id='#{user.id}'"
rescue
# pass, fallback init done above begin block to scope parameters beyond the begin/rescue block
end
- # TODO: modify/copy CSS for notes_sub_error => subscribe_error
- # TODO: modify/copy CSS for subscribe_to_notes => subscribe_to_ontology
spinner = '' + image_tag("spinners/spinner_000000_16px.gif", style: "vertical-align: text-bottom;") + ''
error = ""
- return "#{sub_text} #{spinner} #{error}"
+ "#{sub_text} #{spinner} #{error}"
end
def subscribed_to_ontology?(ontology_acronym, user)
@@ -295,10 +231,11 @@ def ontolobridge_instructions_template(ontology)
# http://stackoverflow.com/questions/1293573/rails-smart-text-truncation
def smart_truncate(s, opts = {})
- opts = {:words => 20}.merge(opts)
+ opts = { words: 20 }.merge(opts)
if opts[:sentences]
- return s.split(/\.(\s|$)+/)[0, opts[:sentences]].map{|s| s.strip}.join('. ') + '. ...'
+ return s.split(/\.(\s|$)+/)[0, opts[:sentences]].map { |s| s.strip }.join('. ') + '. ...'
end
+
a = s.split(/\s/) # or /[ ]+/ to only split on spaces
n = opts[:words]
a[0...n].join(' ') + (a.size > n ? '...' : '')
@@ -309,11 +246,9 @@ def smart_truncate(s, opts = {})
# => '06/27/2010'
def xmldatetime_to_date(xml_date_time_str)
require 'date'
- d = DateTime.xmlschema( xml_date_time_str ).to_date
+ d = DateTime.xmlschema(xml_date_time_str).to_date
# Return conventional US date format:
- return sprintf("%02d/%02d/%4d", d.month, d.day, d.year)
- # Or return "yyyy/mm/dd" format with:
- #return DateTime.xmlschema( xml_date_time_str ).to_date.to_s
+ sprintf("%02d/%02d/%4d", d.month, d.day, d.year)
end
def flash_class(level)
@@ -321,47 +256,43 @@ def flash_class(level)
'notice' => 'alert-info',
'success' => 'alert-success',
'error' => 'alert-danger',
- 'alert' => 'alert-danger'
+ 'alert' => 'alert-danger',
+ 'warning' => 'alert-warning'
}
bootstrap_alert_class[level]
end
- ###BEGIN ruby equivalent of JS code in bp_ajax_controller.
- ###Note: this code is used in concepts/_details partial.
+ # NOTE: The following 4 methods (bp_ont_link, bp_class_link, get_link_for_cls_ajax, get_link_for_ont_ajax) are
+ # the Ruby equivalent of JS code in bp_ajax_controller.js and are used in the concepts/_details partial.
def bp_ont_link(ont_acronym)
- return "/ontologies/#{ont_acronym}"
+ "/ontologies/#{ont_acronym}"
end
def bp_class_link(cls_id, ont_acronym)
ontology_path(id: ont_acronym, p: 'classes', conceptid: cls_id)
end
- def get_link_for_cls_ajax(cls_id, ont_acronym, target=nil)
- # Note: bp_ajax_controller.ajax_process_cls will try to resolve class labels.
+ def get_link_for_cls_ajax(cls_id, ont_acronym, target = nil)
+ # NOTE: bp_ajax_controller.ajax_process_cls will try to resolve class labels.
# Uses 'http' as a more generic attempt to resolve class labels than .include? ont_acronym; the
# bp_ajax_controller.ajax_process_cls will try to resolve class labels and
# otherwise remove the UNIQUE_SPLIT_STR and the ont_acronym.
- if target.nil?
- target = ""
- else
- target = " target='#{target}' "
- end
- if cls_id.start_with? 'http://'
+ target = target.nil? ? '' : " target='#{target}' "
+
+ if cls_id.start_with?('http://', 'https://')
href_cls = " href='#{bp_class_link(cls_id, ont_acronym)}' "
data_cls = " data-cls='#{cls_id}' "
data_ont = " data-ont='#{ont_acronym}' "
- return "#{cls_id}"
+ "#{cls_id}"
else
- return auto_link(cls_id, :all, :target => '_blank')
+ auto_link(cls_id, :all, target: '_blank')
end
end
+
def get_link_for_ont_ajax(ont_acronym)
- # ajax call will replace the acronym with an ontology name (triggered by class='ont4ajax')
+ # Ajax call will replace the acronym with an ontology name (triggered by class='ont4ajax')
href_ont = " href='#{bp_ont_link(ont_acronym)}' "
data_ont = " data-ont='#{ont_acronym}' "
- return "#{ont_acronym}"
+ "#{ont_acronym}"
end
- ###END ruby equivalent of JS code in bp_ajax_controller.
-
-
end
diff --git a/app/helpers/internationalisation_helper.rb b/app/helpers/internationalisation_helper.rb
new file mode 100644
index 0000000000..6bda49f76d
--- /dev/null
+++ b/app/helpers/internationalisation_helper.rb
@@ -0,0 +1,43 @@
+module InternationalisationHelper
+
+ # Implement logic to make the term 'ontology' configurable throughout the portal,
+ # allowing it to be replaced with the variable $RESOURCE_TERM
+ def self.t(*args, **kwargs)
+ return I18n.t(*args, **kwargs) unless $RESOURCE_TERM
+
+ begin
+ original_translation = I18n.t(*args, **kwargs)
+ downcase_translation = original_translation.downcase
+ rescue StandardError => e
+ return e.message
+ end
+
+ term = I18n.t("resource_term.ontology")
+ plural_term = I18n.t("resource_term.ontology_plural")
+ single_term = I18n.t("resource_term.ontology_single")
+ resource = I18n.t("resource_term.#{$RESOURCE_TERM}")
+ resources = I18n.t("resource_term.#{$RESOURCE_TERM}_plural")
+ a_resource = I18n.t("resource_term.#{$RESOURCE_TERM}_single")
+
+ if downcase_translation.include?(term) && resource
+ replacement = resource.capitalize
+ replacement = resource if downcase_translation.include?(term)
+ if downcase_translation.include?(single_term)
+ term = single_term
+ replacement = a_resource
+ end
+ original_translation.gsub(term, replacement)
+ elsif downcase_translation.include?(plural_term) && resources
+ replacement = resources.capitalize
+ replacement = resources if downcase_translation.include?(plural_term)
+ original_translation.gsub(plural_term, replacement)
+ else
+ I18n.t(*args, **kwargs)
+ end
+ end
+
+ # def t(*args, **kwargs)
+ # InternationalisationHelper.t(*args, **kwargs)
+ # end
+
+end
diff --git a/app/helpers/multi_languages_helper.rb b/app/helpers/multi_languages_helper.rb
new file mode 100644
index 0000000000..d12d5dd881
--- /dev/null
+++ b/app/helpers/multi_languages_helper.rb
@@ -0,0 +1,146 @@
+module MultiLanguagesHelper
+
+ def portal_language_help_text
+ t('language.portal_language_help_text')
+ end
+
+ def portal_languages
+ {
+ en: { badge: nil, disabled: false },
+ fr: { badge: 'beta', disabled: false },
+ it: { badge: 'coming', disabled: true },
+ de: { badge: 'coming', disabled: true }
+ }
+ end
+
+ def portal_language_selector
+ languages = portal_languages
+ selected_language = portal_lang
+ selected_language = content_tag(:span, selected_language.upcase, data: { controller: 'tooltip' }, title: portal_language_help_text)
+ render DropdownButtonComponent.new do |d|
+ d.header { selected_language }
+ d.section(divide: false, selected_index: languages.find_index(selected_language)) do |s|
+ languages.each do |lang, metadata|
+ s.item do
+ text = content_tag(:div, class: 'd-flex align-items-center') do
+ content_tag(:span, render(LanguageFieldComponent.new(value: lang, auto_label: true)), class: 'mr-1') + beta_badge(metadata[:badge])
+ end
+ link_options = { data: { turbo: false } }
+
+ if metadata[:disabled]
+ link_options[:class] = 'disabled-link'
+ link_options[:disabled] = 'disabled'
+ end
+
+ link_to(text, "/locale/#{lang}", link_options)
+ end
+ end
+
+ end
+ end
+ end
+
+ def search_language_help_text
+ content_tag(:div, style: 'width: 300px; text-align: center') do
+ t('language.search_language_help_text')
+ end
+ end
+
+ def search_languages
+ # top ten spoken languages
+ portal_languages.keys + %w[zh es hi ar bn pt ru ur id]
+ end
+
+ def language_hash(concept_label, multiple: false)
+ if concept_label.is_a?(Array)
+ return concept_label.first unless multiple
+ return concept_label
+ end
+
+ return concept_label.to_h.reject { |key, _| %i[links context].include?(key) } if concept_label.is_a?(OpenStruct)
+
+ concept_label
+ end
+
+ def sorted_labels(labels)
+ Array(labels).sort_by { |label| label['prefLabel'].is_a?(String) ? label['prefLabel'] : label['prefLabel'].last }
+ end
+
+ def select_language_label(concept_label, platform_languages = %i[en fr])
+ concept_value = nil
+
+ concept = language_hash(concept_label)
+
+ return ['@none', concept] if concept.is_a?(String)
+
+ concept = concept.to_h
+
+ platform_languages.each do |lang|
+ if concept[lang]
+ concept_value = [lang, concept[lang]]
+ break
+ end
+ end
+
+ concept_value || concept.to_a.first
+ end
+
+ def main_language_label(label)
+ select_language_label(label)&.last
+ end
+
+ def selected_language_label(label)
+ language_hash(label).values.first
+ end
+
+ def content_language_selector(id: 'content_language', name: 'content_language')
+ languages, selected = content_languages
+ select_tag(name, options_for_select(languages, selected || 'all'), class: "form-select",
+ data: { controller: "language-change", 'language-change-section-value': "classes", action: "change->language-change#dispatchLangChangeEvent" }) if languages&.length > 1
+ end
+
+ def content_languages(submission = @submission || @submission_latest)
+ current_lang = request_lang(submission).downcase
+ submission_lang = submission_languages(submission)
+ # Transform each language into a select option
+ submission_lang = submission_lang.map do |lang|
+ lang = lang.split('/').last.upcase
+ lang = ISO_639.find(lang.to_s.downcase)
+ next nil unless lang
+ [lang.english_name, lang.alpha2]
+ end.compact
+
+ [submission_lang, current_lang]
+ end
+
+ def portal_lang
+ session[:locale] || 'en'
+ end
+
+ def request_lang(submission = @submission || @submission_latest)
+ lang = params[:language] || params[:lang]
+ lang = submission_languages(submission)&.first unless lang
+ lang = portal_lang unless lang
+ lang
+ end
+
+ def lang_code(code_in)
+ code_out = code_in
+ case code_in
+ when 'en'
+ code_out = 'us'
+ when 'ar'
+ code_out = 'sa'
+ when 'hi'
+ code_out = 'in'
+ when 'ur'
+ code_out = 'pk'
+ when 'zh'
+ code_out = 'cn'
+ when 'ja'
+ code_out = 'jp'
+ end
+ code_out
+ end
+
+end
diff --git a/app/helpers/ontologies_helper.rb b/app/helpers/ontologies_helper.rb
index 88ea877d94..e255fdedd4 100644
--- a/app/helpers/ontologies_helper.rb
+++ b/app/helpers/ontologies_helper.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
+require 'iso-639'
module OntologiesHelper
+
+ LANGUAGE_FILTERABLE_SECTIONS = %w[classes properties].freeze
+
def additional_details
return '' if $ADDITIONAL_ONTOLOGY_DETAILS.nil? || $ADDITIONAL_ONTOLOGY_DETAILS[@ontology.acronym].nil?
@@ -158,4 +162,34 @@ def change_requests_enabled?(ontology_acronym)
Rails.configuration.change_request[:ontologies].include? ontology_acronym.to_sym
end
+
+ def current_section
+ (params[:p]) ? params[:p] : 'summary'
+ end
+
+ def ontology_data_sections
+ LANGUAGE_FILTERABLE_SECTIONS
+ end
+
+ def ontology_data_section?(section_title = current_section)
+ ontology_data_sections.include?(section_title)
+ end
+
+ def language_selector_tag(name)
+ content_language_selector(id: name, name: name)
+ end
+
+ def submission_languages(submission = @submission)
+ Array(submission&.naturalLanguage).map { |natural_language| natural_language.split('/').last }.compact
+ end
+
+ def abbreviations_to_languages(abbreviations)
+ # Use iso-639 gem to convert language codes to their English names
+ languages = abbreviations.map do |abbr|
+ language = ISO_639.find_by_code(abbr) || ISO_639.find_by_english_name(abbr)
+ language ? language.english_name : abbr
+ end
+ languages.sort
+ end
+
end
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
new file mode 100644
index 0000000000..25f5fa46fe
--- /dev/null
+++ b/app/helpers/users_helper.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module UsersHelper
+ def custom_ontology_set_intro_text
+ tag.div do
+ concat(tag.p do
+ concat(tag.span('Customize your display: ', class: 'fw-bold text-muted'))
+ concat(tag.span("pick the ontologies you want to see and #{$SITE} will hide all other ontologies.",
+ class: 'text-muted'))
+ end)
+ concat(tag.p('Please note: you must be logged in to use this feature', class: 'fst-italic text-muted'))
+ end
+ end
+
+ def custom_ontology_set_slice_text
+ tag.p class: 'mb-5' do
+ concat('Please visit the ')
+ concat(link_to('main site', "#{$UI_URL}/account"))
+ concat(' to modify your custom ontology set')
+ end
+ end
+end
diff --git a/app/javascript/controllers/clipboard_controller.js b/app/javascript/controllers/clipboard_controller.js
new file mode 100644
index 0000000000..30320b5e30
--- /dev/null
+++ b/app/javascript/controllers/clipboard_controller.js
@@ -0,0 +1,16 @@
+import { Controller } from "@hotwired/stimulus"
+
+// Connects to data-controller="clipboard"
+export default class extends Controller {
+ static targets = ['source', 'copiedIndicator']
+
+ copy() {
+ navigator.clipboard.writeText(this.sourceTarget.textContent);
+
+ this.copiedIndicatorTarget.classList.remove('hidden');
+
+ setTimeout(() => {
+ this.copiedIndicatorTarget.classList.add('hidden');
+ }, 2000);
+ }
+}
diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js
index 373c3edc28..273754277c 100644
--- a/app/javascript/controllers/index.js
+++ b/app/javascript/controllers/index.js
@@ -3,3 +3,10 @@
// ./bin/rails generate stimulus controllerName
import { application } from "./application"
+
+import LanguageChangeController from "./language_change_controller"
+application.register("language-change", LanguageChangeController)
+
+import ClipboardController from "./clipboard_controller"
+application.register("clipboard", ClipboardController)
+
diff --git a/app/javascript/controllers/language_change_controller.js b/app/javascript/controllers/language_change_controller.js
new file mode 100644
index 0000000000..b1fc34aa5f
--- /dev/null
+++ b/app/javascript/controllers/language_change_controller.js
@@ -0,0 +1,47 @@
+import { Controller } from "@hotwired/stimulus"
+
+// Connects to data-controller="language-change"
+export default class extends Controller {
+
+
+ connect() {
+ // can be used for debugging
+ // console.log(this.element.value);
+ jQuery(document).data().bp.ont_viewer.lang = this.element.value;
+ }
+
+ dispatchLangChangeEvent() {
+ jQuery(document).data().bp.ont_viewer.lang = this.element.value;
+
+ var url = window.location.href;
+ url = this.removeURLParameter(url, 'lang');
+ if (url.indexOf('?') > -1) {
+ url += '&lang=' + this.element.value;
+ } else {
+ url += '?lang=' + this.element.value;
+ }
+ jQuery.blockUI({ message: 'Switching language...
', showOverlay: true });
+ window.location.href = url;
+ }
+
+ removeURLParameter(url, parameter) {
+ //prefer to use l.search if you have a location/link object
+ var urlparts = url.split('?');
+
+ if (urlparts.length >= 2) {
+ var prefix = encodeURIComponent(parameter) + '=';
+ var pars = urlparts[1].split(/[&;]/g);
+
+ //reverse iteration as may be destructive
+ for (var i = pars.length; i-- > 0;) {
+ //idiom for string.startsWith
+ if (pars[i].lastIndexOf(prefix, 0) !== -1) {
+ pars.splice(i, 1);
+ }
+ }
+ return urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');
+ }
+ return url;
+ }
+
+}
diff --git a/app/views/concepts/_child_nodes.html.haml b/app/views/concepts/_child_nodes.html.haml
index 79107a3cb3..b734cc5944 100644
--- a/app/views/concepts/_child_nodes.html.haml
+++ b/app/views/concepts/_child_nodes.html.haml
@@ -1,8 +1,9 @@
- output =""
- for child in @children
- icons = child.relation_icon(@concept)
- - output << " #{child.prefLabel} #{icons}"
+ - output << " #{child.prefLabel} #{icons}"
+
- if child.hasChildren
- - output << ""
+ - output << ""
- output << ""
= raw output
diff --git a/app/views/concepts/_details.html.haml b/app/views/concepts/_details.html.haml
index 4bc9657688..cb0ff44494 100644
--- a/app/views/concepts/_details.html.haml
+++ b/app/views/concepts/_details.html.haml
@@ -25,7 +25,11 @@
%tr
%td Preferred Name
%td
- %p= @concept.prefLabel({:use_html => true}).html_safe
+ %p
+ - if @concept.prefLabel({:use_html => false}).to_s.empty?
+ %div.alert.alert-warning= 'No preferred name provided for selected language'
+ - else
+ = @concept.prefLabel({:use_html => true}).html_safe
%td
%tr
%td Synonyms
diff --git a/app/views/concepts/_request_term.html.haml b/app/views/concepts/_request_term.html.haml
index 7185c38a35..7c3bed4a93 100644
--- a/app/views/concepts/_request_term.html.haml
+++ b/app/views/concepts/_request_term.html.haml
@@ -36,11 +36,7 @@
var g_prefLabel;
jQuery(document).ready(function() {
- g_prefLabel = '#{@concept.prefLabel({:use_html => false}).html_safe}';
-
- if (!g_prefLabel) {
- g_prefLabel = '#{@concept.id}';
- }
+ g_prefLabel = '#{@concept.prefLabel({:use_html => false}).to_s.empty? ? @concept.id : @concept.prefLabel({:use_html => false}).html_safe}';
var isPopulated = window.localStorage.getItem('request_term_form_populated');
if (isPopulated) {
diff --git a/app/views/layouts/_ontology_viewer.html.haml b/app/views/layouts/_ontology_viewer.html.haml
index 64f4899d0c..124ecf014e 100644
--- a/app/views/layouts/_ontology_viewer.html.haml
+++ b/app/views/layouts/_ontology_viewer.html.haml
@@ -36,6 +36,9 @@
jQuery(document).data().bp.ont_viewer.purl_prefix = "#{(Rails.configuration.settings.purl[:enabled] ? Rails.configuration.settings.purl[:prefix]+"/"+@ontology.acronym : '')}";
jQuery(document).data().bp.ont_viewer.concept_name_title = (jQuery(document).data().bp.ont_viewer.concept_name == "") ?
"" : " - " + jQuery(document).data().bp.ont_viewer.concept_name;
+ jQuery(document).data().bp.ont_viewer.lang = "#{request_lang(sub)}";
+ jQuery(document).data().bp.ont_viewer.submission_lang = #{submission_languages(sub).to_json.html_safe};
+ jQuery(document).data().bp.ont_viewer.lang_sections = #{ontology_data_sections.to_json.html_safe};
-# Modal dialog for creating a new mapping (must reside in a top-level position in the document to display properly).
%div#createNewMappingModal{class: "modal fade", tabindex: "-1", "aria-labelledby": "createNewMappingLabel"}
@@ -139,6 +142,8 @@
class: "nav-link", type: 'button', role: "tab",
data: {bp_ont_page: "widgets", "bs-toggle": "tab", "bs-target": "#ont_widgets_content"},
aria: {controls: "ont_widgets_content", selected: "false"})
+ %li{style: "display: #{ontology_data_section? ? 'block' : 'none'}", class: 'nav-item lang-dropdown', role: 'presentation'}
+ = language_selector_tag(:content_language)
%div.card-body
-# Tab panes for displaying ontology content sections
%div.tab-content{id: "ontology_content"}
@@ -160,7 +165,6 @@
%div.tab-pane{id: "ont_widgets_content", role: "tabpanel", aria: {labelledby: "ont-widgets-tab"}}
- if content_section.eql?("widgets")
= yield
-
- if Rails.env.appliance?
= render partial: "footer_appliance"
diff --git a/app/views/login/index.html.erb b/app/views/login/index.html.erb
deleted file mode 100644
index 08110c66a8..0000000000
--- a/app/views/login/index.html.erb
+++ /dev/null
@@ -1,34 +0,0 @@
-<%@title = "Login"%>
-
-<%= form_for(:user, :url => {:controller => 'login',:action=>'create'}) do |f| %>
-<%unless @errors.nil?%>
-
-Errors On Form
-
-
-<%for error in @errors%>
-- <%=error%>
-<%end%>
-
-
-
-<%end%>
-
-
- Not Registered Yet? <%=link_to "Sign Up", new_user_path%>
- <%=link_to "Lost Password", '/lost_pass'%>
-
-
-<% end %>
\ No newline at end of file
diff --git a/app/views/login/index.html.haml b/app/views/login/index.html.haml
new file mode 100644
index 0000000000..dc5e593b69
--- /dev/null
+++ b/app/views/login/index.html.haml
@@ -0,0 +1,29 @@
+- @title = "Login"
+
+%div.signin
+ = form_with scope: :user, url: login_index_path, class: 'form-signin' do |f|
+ %h4.mb-4
+ = "Log in to #{$SITE}"
+
+ -# TODO: display errors in a standard Rails flash message
+ - if @errors.present?
+ %div.enable-lists
+ Errors on form:
+ %ul
+ - for error in @errors
+ %li= error
+
+ %div.form-floating.mb-3
+ = f.text_field(:username, class: 'form-control', placeholder: 'Username', required: true)
+ = f.label(:username)
+ %div.form-floating.mb-3
+ = f.password_field(:password, class: 'form-control', placeholder: 'Password', required: true,
+ autocomplete: 'current-password')
+ = f.label(:password)
+ %div.d-grid.mb-3
+ = submit_tag('Log in', class: 'btn btn-lg btn-primary')
+ %p.text-muted.mb-1
+ = "New #{$SITE} user?"
+ = link_to('Create account', new_user_path)
+ %p.text-muted
+ = link_to('Forgot your password?', lost_pass_path)
diff --git a/app/views/login/lost_password.html.erb b/app/views/login/lost_password.html.erb
deleted file mode 100644
index dbbf4338eb..0000000000
--- a/app/views/login/lost_password.html.erb
+++ /dev/null
@@ -1,22 +0,0 @@
-<%= form_for(:user , :url=>{:controller=>'login',:action=>'send_pass'}) do%>
-
-
-
-
-* required
-
-
-
-<%end%>
\ No newline at end of file
diff --git a/app/views/login/lost_password.html.haml b/app/views/login/lost_password.html.haml
new file mode 100644
index 0000000000..d40b2be6e9
--- /dev/null
+++ b/app/views/login/lost_password.html.haml
@@ -0,0 +1,13 @@
+%div.password-reset
+ = form_with scope: :user , url: login_send_pass_path do |f|
+ %h3 Forgot your password?
+ %p.text-muted.mb-5
+ = "Enter your email and #{$SITE} username to receive a password reset link."
+ %div.mb-3
+ = f.label :email, 'Email', class: 'form-label'
+ = f.email_field :email, class: 'form-control'
+ %div.mb-3
+ = f.label :account_name, 'Username', class: 'form-label'
+ = f.text_field :account_name, class: 'form-control'
+ %div
+ = submit_tag 'Reset password', class: 'btn btn-primary'
diff --git a/app/views/ontologies/_metadata.html.haml b/app/views/ontologies/_metadata.html.haml
index aa5c44a6dc..b166fda198 100644
--- a/app/views/ontologies/_metadata.html.haml
+++ b/app/views/ontologies/_metadata.html.haml
@@ -49,6 +49,10 @@
%tr
%td Groups
%td= groups.map {|g| groups_hash[g].name}.sort.join(", ")
+ - unless @submission_latest.naturalLanguage.empty?
+ %tr
+ %td Language
+ %td= abbreviations_to_languages(@submission_latest.naturalLanguage).join(", ")
= raw additional_details
-# Submissions pane
diff --git a/app/views/ontologies/_treeview.html.haml b/app/views/ontologies/_treeview.html.haml
index 3640b54510..20db396a8b 100644
--- a/app/views/ontologies/_treeview.html.haml
+++ b/app/views/ontologies/_treeview.html.haml
@@ -2,4 +2,4 @@
%ul.simpleTree
%li.root
%ul
- = draw_tree(@root, @concept.id) # application_helper::draw_tree
+ = draw_tree(@root, @concept.id, @submission) # application_helper::draw_tree
diff --git a/app/views/passwords/edit.html.haml b/app/views/passwords/edit.html.haml
new file mode 100644
index 0000000000..83b776e7d8
--- /dev/null
+++ b/app/views/passwords/edit.html.haml
@@ -0,0 +1,18 @@
+%div.container
+ %div.edit-user-info
+ = form_with url: password_path, method: 'patch', class: 'my-4' do |f|
+ - if @errors.present?
+ %div{class: 'alert alert-danger mb-4'}
+ - for error in @errors
+ %div= error
+ %h2{class: 'pb-2 border-bottom'} Change password
+ = tag.p "Enter a new password for your #{$SITE} account (#{@user.username})", class: 'text-muted mb-4'
+ %div.mb-3
+ = f.label :password, 'New password', class: 'form-label'
+ = f.password_field :password, class: 'form-control', required: 'true'
+ %div.mb-4
+ = f.label :password_confirmation, 'Confirm new password', class: 'form-label'
+ = f.password_field :password_confirmation, class: 'form-control', required: 'true'
+ %div
+ = submit_tag('Update', class: 'btn btn-primary me-1')
+ = link_to 'Cancel', user_path(@user.username), class: 'btn btn-primary'
diff --git a/app/views/search/_concept_preview.html.erb b/app/views/search/_concept_preview.html.erb
deleted file mode 100644
index 5d8cdc1fe1..0000000000
--- a/app/views/search/_concept_preview.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-
\ No newline at end of file
diff --git a/app/views/search/_concepts.html.erb b/app/views/search/_concepts.html.erb
deleted file mode 100644
index b0593ccee0..0000000000
--- a/app/views/search/_concepts.html.erb
+++ /dev/null
@@ -1,22 +0,0 @@
-<%if @concepts.size > 0%>
-
-
-
-
-
-
-
-
Comment
<%=text_area(:mapping, :comment, :size => "30x10")%>
-
-
-
- <%= select("mapping", "directionality", { "Bidirectional" => "bidirectional", "Unidirectional" => "unidirectional" })%>
- <%= submit_tag "Create", :class=>'blueButton'%>
-
-<%else%>
- No Results Found
-<%end%>
\ No newline at end of file
diff --git a/app/views/search/_results.html.erb b/app/views/search/_results.html.erb
deleted file mode 100644
index 314707ad38..0000000000
--- a/app/views/search/_results.html.erb
+++ /dev/null
@@ -1,69 +0,0 @@
-
-<%if @results.size > 0%>
-
- <%if params[:page].to_i > 1 %>
- << Previous Page
-
- <%end%>
- Page <%=params[:page] || 1%> of <%=@pages%>
- <%if !params[:page].to_i.eql?(@pages.to_i)%>
- Next Page >>
-
- <%end%>
-
-
-
-
-
- <%if params[:page].to_i >1 %> << Previous Page <%end%> Page <%=params[:page] || 1%> of <%=@pages%> <%if !params[:page].to_i.eql?(@pages.to_i)%> Next Page >><%end%>
- |
-
-
-
- Class Name |
- Found In |
- Ontology |
-
-
- <%for result in @results%>
- <%begin
- #catch exceptions and dont draw row
- row = "
- #{link_to highlight(result[:contents],@keyword), uri_url(:ontology => result[:ontologyVersionId], :conceptid => result[:conceptIdShort]), :onclick => "YAHOO.tabwait.container.wait.show();"} |
- #{result[:recordType].titleize.gsub("Record Type","")} |
- #{link_to result[:ontologyDisplayLabel], ontology_path(:id=>result[:ontologyVersionId])} |
-
"%>
- <%=row%>
- <%rescue
- end
- %>
- <%end%>
-
-
-
- <%if params[:page].to_i >1 %> << Previous Page <%end%> Page <%=params[:page] || 1%> of <%=@pages%> <%if !params[:page].to_i.eql?(@pages.to_i)%> Next Page >><%end%>
- |
-
-
-
-<%else%>
- No Results Found
-<%end%>
diff --git a/app/views/users/_form.html.haml b/app/views/users/_form.html.haml
deleted file mode 100644
index a3306597fe..0000000000
--- a/app/views/users/_form.html.haml
+++ /dev/null
@@ -1,38 +0,0 @@
-%table.form{:width => "70%"}
- %tr
- %th First Name:
- %td.top= text_field :user, :firstName, value: @user.firstname
- %tr
- %th Last Name:
- %td= text_field :user, :lastName, value: @user.lastname
- %tr
- %th Account Name:*
- %td= text_field :user, :username, value: @user.username
- %tr
- %th Email Address:*
- %td= text_field :user, :email, value: @user.email
- %tr
- %th Re-enter Email Address:*
- %td= text_field :user, :email_confirmation, value: @user.email_confirmation
- %tr
- %th Password:*
- %td= password_field :user, :password, :autocomplete => "off"
- %tr
- %th Re-enter Password:*
- %td= password_field :user, :password_confirmation, :autocomplete => "off"
- - if using_captcha?
- %tr
- %th
- %td= recaptcha_tags
- - unless $ANNOUNCE_LIST.nil? || $ANNOUNCE_LIST.empty?
- %tr
- %td{:colspan => "2", :style => "text-align: right;"}
- %div{:style => "float: right; margin-left: 10px; position: relative; top: 5px;"}
- %input#user_register_mail_list{:checked => "checked", :name => "user[register_mail_list]", :type => "checkbox", :value => "1"}/
- %div{:style => "overflow: hidden; line-height: 12px;"}
- %label{:for => "user_register_mail_list"}
- Register for the #{$SITE} announcements email list
- %br/
- %span{:style => "font-size: x-small;"} (approximately two emails per month -- confirmation via email required)
- %tr
- %td{:colspan => "2", :style => "text-align: right;"}= submit_tag "Create"
diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml
index cd3f31a335..a9476331d9 100644
--- a/app/views/users/edit.html.haml
+++ b/app/views/users/edit.html.haml
@@ -1,32 +1,5 @@
-:css
- .required {
- color: black;
- }
- table.form {
- width: auto;
- }
- table.form td {
- width: 500px;
- }
-
:javascript
- /* refer to input fields by name for rules */
- /* refer to input fields by id for equalTo */
jQuery(document).ready(function() {
- jQuery("#user_info").validate({
- rules: {
- "user[email]": {
- required: true,
- email: true,
- },
- "user[password]": "required",
- "user[password_confirmation]": {
- required: true,
- equalTo: "#user_password",
- }
- }
- })
-
jQuery('#user_info').on('submit', function (event) {
event.preventDefault()
let admin_checkbox = jQuery('input[id=user_admin]')
@@ -52,94 +25,46 @@
})
});
- (function (jQuery) {
- // custom css expression for a case-insensitive contains()
- jQuery.expr[':'].Contains = function(a,i,m){
- return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;
- };
-
- function listFilter(header, list) { // header is any element, list is an unordered list
- // create and add the filter form to the header
- var form = jQuery("