Skip to content

Commit

Permalink
Merge branch 'main' into full-test-suite
Browse files Browse the repository at this point in the history
  • Loading branch information
stuzart committed May 15, 2024
2 parents e153756 + c2dffbb commit b88e239
Show file tree
Hide file tree
Showing 132 changed files with 2,234 additions and 989 deletions.
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ gem 'will_paginate', '~> 3.1'
gem 'yaml_db'
gem 'rails_autolink'
gem 'rfc-822'
gem 'nokogiri', '~> 1.16.2'
gem 'nokogiri', '~> 1.16.5'
#necessary for newer hashie dependency, original api_smith is no longer active
gem 'api_smith', git: 'https://github.com/youroute/api_smith.git', ref: '1fb428cebc17b9afab25ac9f809bde87b0ec315b'
gem 'rdf-virtuoso', '>= 0.2.0'
Expand Down Expand Up @@ -134,7 +134,7 @@ gem 'request_store'

gem 'bundler', '>= 1.8.4'

gem 'ro-crate', '~> 0.5.1'
gem 'ro-crate', '~> 0.5.2'

gem 'rugged'
gem 'i18n-js'
Expand Down
10 changes: 5 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ GEM
nokogiri (~> 1)
rake
mini_mime (1.1.5)
mini_portile2 (2.8.5)
mini_portile2 (2.8.6)
minitest (5.20.0)
minitest-reporters (1.5.0)
ansi
Expand Down Expand Up @@ -492,7 +492,7 @@ GEM
net-protocol
netrc (0.11.0)
nio4r (2.7.0)
nokogiri (1.16.2)
nokogiri (1.16.5)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nori (1.1.5)
Expand Down Expand Up @@ -737,7 +737,7 @@ GEM
json (~> 2.3.0)
ucf (~> 2.0.2)
uuid (~> 2.3)
ro-crate (0.5.1)
ro-crate (0.5.2)
addressable (>= 2.7, < 2.9)
rubyzip (~> 2.0.0)
rsolr (2.5.0)
Expand Down Expand Up @@ -1028,7 +1028,7 @@ DEPENDENCIES
my_responds_to_parent!
mysql2
net-ftp
nokogiri (~> 1.16.2)
nokogiri (~> 1.16.5)
omniauth (~> 2.1.0)
omniauth-github
omniauth-rails_csrf_protection
Expand Down Expand Up @@ -1069,7 +1069,7 @@ DEPENDENCIES
rfc-822
rmagick (= 5.3.0)
ro-bundle (~> 0.3.0)
ro-crate (~> 0.5.1)
ro-crate (~> 0.5.2)
rspec-rails (~> 5.1)
rubocop
ruby-prof
Expand Down
11 changes: 8 additions & 3 deletions app/assets/javascripts/objects_input.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ var ObjectsInput = {

const template = $j(this).data('typeahead-template') || 'typeahead/hint';
opts.templateResult = HandlebarsTemplates[template];
opts.escapeMarkup = function (m) {
return m;
}
opts.escapeMarkup = ObjectsInput.doNothing;
opts.templateSelection = ObjectsInput.escapeSelectionMarkup;

if ($j(this).data('typeahead-query-url')) {
opts.ajax={
Expand All @@ -47,6 +46,12 @@ var ObjectsInput = {
opts
);
});
},
doNothing: function (m) {
return m;
},
escapeSelectionMarkup: function (m) {
return jQuery.fn.select2.defaults.defaults.escapeMarkup(m.text);
}
}
$j(document).ready(function () {
Expand Down
65 changes: 47 additions & 18 deletions app/assets/javascripts/single_page/dynamic_table.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,33 @@ const defaultCols = [{
}
}];

// Sanitizes input data to prevent XSS attacks
// https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
function sanitizeHTML(str) {
return str.replace(/[&<>"']/g, function(match) {
return {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;'
}[match];
});
}

function sanitizeData(data) {
if (typeof data === 'string' && data !== "") {
return sanitizeHTML(data);
} else if(typeof data === 'array'){
return data.forEach((e) => {
sanitizeData(e);
});
} else {
// Handle other data types or nested objects/arrays if necessary
return data;
}
}

const objectInputTemp = '<input type="hidden" name="_NAME_[]" id="inpt-_NAME_" value="" autocomplete="off" />' +
'<select name="_NAME_[]" id="select-_NAME_" class="form-control _EXTRACLASS_" title="_TITLE_" data-role="seek-objectsinput" ' +
'data-tags-limit="100" _MULTIPLE?_ style="background-color: coral;" data-typeahead-template="_TYPEHEAD_"' +
Expand Down Expand Up @@ -59,12 +86,13 @@ const handleSelect = (e) => {
}

c["render"] = function(data_, type, full, meta) {
sanitizedData = sanitizeData(data_);
if(c.linked_sample_type){
data = data_ && Array.isArray(data_) ? data_ : [data_];
data = sanitizedData && Array.isArray(sanitizedData) ? sanitizedData : [sanitizedData];
data = data[0]?.id ? data : [];
return inputObjectsInput(c, data, options, linkedSamplesUrl);
} else if(c.is_cv_list && data_ !== "#HIDDEN"){
data = data_ && Array.isArray(data_) ? data_ : [data_];
} else if(c.is_cv_list && sanitizedData !== "#HIDDEN"){
data = sanitizedData && Array.isArray(sanitizedData) ? sanitizedData : [sanitizedData];
data = data.map((e) => {
if (e?.id){
return e.id
Expand All @@ -73,10 +101,10 @@ const handleSelect = (e) => {
}
});
return cvListObjectsInput(c, data, options, cvUrl);
} else if (data_ === "#HIDDEN") {
} else if (sanitizedData === "#HIDDEN") {
return "<em><small>Hidden</small></em>";
} else {
return data_;
return sanitizedData;
}
};
c["createdCell"] = function(td, cellData, rowData, row, col) {
Expand Down Expand Up @@ -162,7 +190,7 @@ const handleSelect = (e) => {
$j.each(sampleTypes, (i, s) => {
if (!isNaN(s)) {
const colIdxs = this.table.columns(`${s}:name`)[0];
if (colIdxs.length) colIdxs.push(colIdxs[0] - 1);
if (colIdxs.length) colIdxs.push(colIdxs[0] - 1, colIdxs[0] - 2);
this.table.column(function(idx, data, node) {
if (colIdxs.includes(idx)) $j(node).addClass(`sp-variant-${i % 2}`);
});
Expand Down Expand Up @@ -435,6 +463,7 @@ const handleSelect = (e) => {
};
})(jQuery);

// Highlights the column if the attribute is a title
function highlightTitleCol(table) {
table.settings()[0].aoColumns.forEach((c, i) => {
if (c.is_title) $j(table.column(i).nodes()).addClass("highlight");
Expand Down Expand Up @@ -546,11 +575,11 @@ function inputObjectsInput(column, data, options, url){
if (isHiddenInput) {
return `<option selected="selected" title="ID: hidden" value="hidden">hidden</option>`
} else {
return `<option selected="selected" title="ID: ${e.id}" value="${e.id}">${e.title}</option>`
return `<option selected="selected" title="ID: ${e.id}" value="${e.id}">${sanitizeData(e.title)}</option>`
}
}).join("");
if (options.readonly) {
return data.map((e) => `<span title="ID: ${e.id}" class="badge">${e.title}</span>`).join(" ");
return data.map((e) => `<span title="ID: ${e.id}" class="badge">${sanitizeData(e.title)}</span>`).join(" ");
} else {
const typeaheadTemplate = 'typeahead/single_pages_samples'
const objectInputName = data.map((e) => e.id).join('-') + '-' + crypto.randomUUID();
Expand Down Expand Up @@ -582,16 +611,16 @@ function inputObjectsInput(column, data, options, url){
}

function cvListObjectsInput(column, data, options, url){
const existingOptions = data.map((e) => `<option selected="selected" value="${e}">${e}</option>`);
if (options.readonly) {
return data.map((e) => `<span title="ID: ${e}" class="badge">${e}</span>`).join(" ");
} else {
const typeaheadTemplate = 'typeahead/controlled_vocab_term';
const objectInputName = data.map((e) => e.title).join('-') + '-' + crypto.randomUUID();
const extraClass = '';
const titleText = '';
const allowNewItems = column.cv_allows_free_text;
setTimeout(ObjectsInput.init);
const existingOptions = data.map((e) => `<option selected="selected" value="${sanitizeData(e)}">${sanitizeData(e)}</option>`);
if (options.readonly) {
return data.map((e) => `<span title="ID: ${sanitizeData(e)}" class="badge">${sanitizeData(e)}</span>`).join(" ");
} else {
const typeaheadTemplate = 'typeahead/controlled_vocab_term';
const objectInputName = data.map((e) => sanitizeData(e)).join('-') + '-' + crypto.randomUUID();
const extraClass = '';
const titleText = '';
const allowNewItems = column.cv_allows_free_text;
setTimeout(ObjectsInput.init);

return objectInputTemp
.replace(/_NAME_/g, objectInputName)
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -578,9 +578,11 @@ def get_parent_resource
parent_id_param = request.path_parameters.keys.detect { |k| k.to_s.end_with?('_id') }
if parent_id_param
parent_type = parent_id_param.to_s.chomp('_id')
parent_class = safe_class_lookup(parent_type.camelize)
parent_class = safe_class_lookup(parent_type.camelize, raise: false)
if parent_class
@parent_resource = parent_class.find(params[parent_id_param])
else
error('Parent resource not recognized','Parent resource not recognized')
end
end
end
Expand Down
22 changes: 18 additions & 4 deletions app/controllers/extended_metadata_types_controller.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
class ExtendedMetadataTypesController < ApplicationController


before_action :is_user_admin_auth, except: [:form_fields, :show]
respond_to :json
before_action :is_user_admin_auth, except: [:form_fields, :show, :index]
before_action :find_requested_item, only: [:administer_update, :show]

include Seek::IndexPager

# generated for form, to display fields for selected metadata type
def form_fields
Expand All @@ -30,6 +29,21 @@ def show
end
end

def index
@extended_metadata_types = ExtendedMetadataType.all.reject { |type| type.supported_type == 'ExtendedMetadata' }
respond_to do |format|
format.json do
render json: @extended_metadata_types,
each_serializer: SkeletonSerializer,
links: json_api_links,
meta: {
base_url: Seek::Config.site_base_host,
api_version: ActiveModel::Serializer.config.api_version
}
end
end
end

def administer_update
@extended_metadata_type.update(extended_metadata_type_params)
unless @extended_metadata_type.save
Expand Down
7 changes: 7 additions & 0 deletions app/controllers/git_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class GitController < ApplicationController
before_action :fetch_git_version
before_action :get_tree, only: [:tree]
before_action :get_blob, only: [:blob, :download, :raw]
before_action :check_fetched, only: [:download, :raw]

user_content_actions :raw

Expand Down Expand Up @@ -257,6 +258,12 @@ def log_event
end
end

def check_fetched
if @blob.remote? && !@blob.fetched?
render_git_error('This file is held externally.', status: 404)
end
end

# # Rugged does not allow streaming blobs
# def stream_blob(blob, filename)
# response.headers['Content-Disposition'] = "attachment; filename=#{filename}"
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/presentations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class PresentationsController < ApplicationController
before_action :presentations_enabled?
before_action :find_assets, :only => [ :index ]
before_action :find_and_authorize_requested_item, :except => [ :index, :new, :create, :preview,:update_annotations_ajax]
before_action :find_display_asset, :only=>[:show, :download]
before_action :find_display_asset, :only=>[:show, :explore, :download]

include Seek::Publishing::PublishingCommon

Expand Down
1 change: 1 addition & 0 deletions app/controllers/projects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ProjectsController < ApplicationController
include CommonSweepers
include Seek::DestroyHandling
include Seek::Projects::Population
include Seek::AnnotationCommon

before_action :login_required, only: [:guided_join, :guided_create, :guided_import, :request_join, :request_create, :request_import,
:administer_join_request, :respond_join_request,
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/search_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def determine_query
@search_query = ActionController::Base.helpers.sanitize(search_params[:q] || search_params[:search_query])
@search = @search_query # used for logging, and logs the origin search query - see ApplicationController#log_event
@search_query ||= ''
@search_query = Seek::Search::SearchTermFilter.filter @search_query
@search_query.strip!
raise InvalidSearchException, 'Query string is empty or blank' if @search_query.blank?
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/studies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def batch_create
# e.g: Study.new(title: 'title', investigation: investigations(:metabolomics_investigation), policy: FactoryBot.create(:private_policy))
# study.policy = Policy.create(name: 'default policy', access_type: 1)
# render plain: params[:studies].inspect
metadata_types = ExtendedMetadataType.where(title: 'MIAPPE metadata', supported_type: 'Study').last
metadata_types = ExtendedMetadataType.where(title: ExtendedMetadataType::MIAPPE_TITLE, supported_type: 'Study').last
studies_length = params[:studies][:title].length
studies_uploaded = false
data_file_uploaded = false
Expand Down
29 changes: 13 additions & 16 deletions app/controllers/workflows_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
require 'ro_crate'

class WorkflowsController < ApplicationController
include Seek::IndexPager
include Seek::AssetsCommon

before_action :workflows_enabled?
before_action :find_assets, only: [:index]
before_action :find_and_authorize_requested_item, except: [:index, :new, :create, :preview, :update_annotations_ajax]
before_action :find_display_asset, only: [:show, :download, :diagram, :ro_crate, :edit_paths, :update_paths]
before_action :find_display_asset, only: [:show, :download, :diagram, :ro_crate, :ro_crate_metadata, :edit_paths, :update_paths]
before_action :login_required, only: [:create, :create_version, :new_version,
:create_from_files, :create_from_ro_crate,
:create_metadata, :provide_metadata, :create_from_git, :create_version_from_git]
Expand All @@ -17,11 +19,11 @@ class WorkflowsController < ApplicationController
include RoCrateHandling
include Legacy::WorkflowSupport

api_actions :index, :show, :create, :update, :destroy, :ro_crate, :create_version
api_actions :index, :show, :create, :update, :destroy, :ro_crate, :ro_crate_metadata, :create_version

rescue_from ROCrate::ReadException do |e|
logger.error("Error whilst attempting to read RO-Crate metadata for #{@workflow&.id}.")
message = "Couldn't read RO-Crate metadata. Check the file is valid."
logger.error("Error whilst attempting to read RO-Crate metadata for Workflow #{@workflow&.id}: #{e.exception.class.name} #{e.message}")
message = "Couldn't read RO-Crate metadata - check the RO-Crate is valid: #{e.message}"
respond_to do |format|
format.html do
flash[:error] = message
Expand All @@ -31,18 +33,6 @@ class WorkflowsController < ApplicationController
end
end

rescue_from ROCrate::WriteException do |e|
exception_notification(500, e) unless Rails.application.config.consider_all_requests_local
message = "Couldn't generate RO-Crate. Check the ro-crate-metadata.json file is valid."
respond_to do |format|
format.html do
flash[:error] = message
redirect_to workflow_path(@workflow)
end
format.json { render json: { title: 'RO-Crate Write Error', detail: message }, status: :internal_server_error }
end
end

def new_git_version
@git_version = @workflow.latest_git_version.next_version(mutable: !@git_repository&.remote?)

Expand Down Expand Up @@ -268,6 +258,13 @@ def ro_crate
"workflow-#{@workflow.id}-#{@display_workflow.version}.crate.zip")
end

def ro_crate_metadata
metadata = @display_workflow.ro_crate.metadata
json = metadata.generate
response.headers['Content-Length'] = json.length.to_s
send_data(json, filename: metadata.id, type: 'application/json', disposition: 'inline')
end

def edit_paths

end
Expand Down
16 changes: 0 additions & 16 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -273,22 +273,6 @@ def contributor(contributor, _avatar = false, _size = 100, _you_text = false)
contributor_name_link.html_safe
end

# this helper is to be extended to include many more types of objects that can belong to the
# user - for example, SOPs and others
def mine?(thing)
return false if thing.nil?
return false unless logged_in?

c_id = current_user.id.to_i

case thing.class.name
when 'Person'
return (current_user.person.id == thing.id)
else
return false
end
end

def link_to_draggable(link_name, url, link_options = {})
link_to(link_name, url, link_options)
end
Expand Down
Loading

0 comments on commit b88e239

Please sign in to comment.