diff --git a/VERSION b/VERSION index 6fee2fedb..2a0ba77cc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.22.2 +1.22.4 diff --git a/app/assets/javascripts/application.js.erb b/app/assets/javascripts/application.js.erb index b2f1ff666..8c5e80ee8 100644 --- a/app/assets/javascripts/application.js.erb +++ b/app/assets/javascripts/application.js.erb @@ -41,6 +41,7 @@ //= require repository_columns/index //= require perfect-scrollbar.min //= require shared/inline_editing +//= require shared/barcode_search //= require activestorage //= require global_activities/side_pane //= require protocols/header diff --git a/app/assets/javascripts/my_modules/repositories.js b/app/assets/javascripts/my_modules/repositories.js index ba38e0d9e..e6e8571da 100644 --- a/app/assets/javascripts/my_modules/repositories.js +++ b/app/assets/javascripts/my_modules/repositories.js @@ -172,6 +172,7 @@ var MyModuleRepositories = (function() { var dataTableWrapper = $(tableContainer).closest('.dataTables_wrapper'); DataTableHelpers.initLengthApearance(dataTableWrapper); DataTableHelpers.initSearchField(dataTableWrapper, I18n.t('repositories.show.filter_inventory_items')); + $('').appendTo($('.search-container')); dataTableWrapper.find('.main-actions, .pagination-row').removeClass('hidden'); if (options.assign_mode) { renderFullViewAssignButtons(); diff --git a/app/assets/javascripts/repositories/show.js b/app/assets/javascripts/repositories/show.js index f03fe0021..76ac28dd1 100644 --- a/app/assets/javascripts/repositories/show.js +++ b/app/assets/javascripts/repositories/show.js @@ -174,27 +174,6 @@ $('.create-new-repository').initSubmitModal('#create-repo-modal', 'repository'); - $('.repository-show').on('click', '.barcode-scanner', function() { - var search = $('.search-container .search-field'); - var input = $('').attr('type', 'text').css('opacity', 0).appendTo('body'); - search.val(''); - search.attr('disabled', true).addClass('barcode-mode'); - - input.focus(); - input.one('change', function() { - search.val($(this).val()); - search.trigger('keyup'); - $(document).click(); - }); - - setTimeout(function() { - $(document).one('click', function() { - search.attr('disabled', false).removeClass('barcode-mode'); - input.remove(); - }); - }); - }); - function initArchivingActionsInDropdown() { $('.archive-repository-option').on('click', function(event) { event.preventDefault(); diff --git a/app/assets/javascripts/shared/barcode_search.js b/app/assets/javascripts/shared/barcode_search.js new file mode 100644 index 000000000..797f2afb0 --- /dev/null +++ b/app/assets/javascripts/shared/barcode_search.js @@ -0,0 +1,21 @@ +$(document).on('click', '.barcode-scanner', function() { + var search = $('.search-container .search-field'); + var input = $('').attr('type', 'text').css({ position: 'absolute', right: 0, opacity: 0 }) + .appendTo($('.search-container').parent()); + search.val(''); + search.attr('disabled', true).addClass('barcode-mode'); + + input.focus(); + input.one('change', function() { + search.val($(this).val()); + search.trigger('keyup'); + $(document).click(); + }); + + setTimeout(function() { + $(document).one('click', function() { + search.attr('disabled', false).removeClass('barcode-mode'); + input.remove(); + }); + }); +}); diff --git a/app/assets/javascripts/sitewide/bio_eddie.js b/app/assets/javascripts/sitewide/bio_eddie.js index 93137e21b..1bedde823 100644 --- a/app/assets/javascripts/sitewide/bio_eddie.js +++ b/app/assets/javascripts/sitewide/bio_eddie.js @@ -92,6 +92,11 @@ var bioEddieEditor = (function() { } else { saveMolecule(svg, structure, scheduleForRegistration); } + }) + .catch(() => { + if (structure === '$$$$V2.0') { + HelperModule.flashAlertMsg(I18n.t('bio_eddie.empty_molecule_error'), 'danger'); + } }); } @@ -129,7 +134,6 @@ var bioEddieEditor = (function() { bioEddieModal.data('update-url', updateUrl); bioEddieModal.find('.file-name input').val(name); bioEddieModal.modal('show'); - } }; }()); diff --git a/app/assets/stylesheets/repositories.scss b/app/assets/stylesheets/repositories.scss index 0beca2d1d..455ea8bff 100644 --- a/app/assets/stylesheets/repositories.scss +++ b/app/assets/stylesheets/repositories.scss @@ -127,24 +127,6 @@ } } - .barcode-scanner { - cursor: pointer; - position: absolute; - right: 12px; - top: 12px; - } - - .search-container { - .search-field { - padding-right: 32px; - - &.barcode-mode { - background-color: $brand-primary; - opacity: .3; - } - } - } - .main-actions { align-items: center; background-color: $color-white; @@ -596,3 +578,21 @@ max-height: 290px; } } + +.barcode-scanner { + cursor: pointer; + position: absolute; + right: 12px; + top: 12px; +} + +.search-container { + .search-field { + padding-right: 32px; + + &.barcode-mode { + background-color: $brand-primary; + opacity: .3; + } + } +} diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index b779d6118..7d7b804cc 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -38,7 +38,7 @@ module Users return redirect_to after_omniauth_failure_path_for(resource_name) end - user = User.find_by(email: email) + user = User.find_by(email: email.downcase) if user.blank? # Create new user and identity diff --git a/app/models/activity.rb b/app/models/activity.rb index 3a5f0c5be..0a66fe3cf 100644 --- a/app/models/activity.rb +++ b/app/models/activity.rb @@ -74,7 +74,8 @@ class Activity < ApplicationRecord breadcrumbs: {} ) - after_create ->(activity) { Activities::DispatchWebhooksJob.perform_later(activity) } + after_create ->(activity) { Activities::DispatchWebhooksJob.perform_later(activity) }, + if: -> { Rails.application.config.x.webhooks_enabled } def self.activity_types_list activity_list = type_ofs.map do |key, value| diff --git a/app/models/user.rb b/app/models/user.rb index c53ac84d0..89df69ddf 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -293,6 +293,7 @@ class User < ApplicationRecord foreign_key: :resource_owner_id, dependent: :delete_all + before_validation :downcase_email! before_destroy :destroy_notifications def name @@ -679,6 +680,12 @@ class User < ApplicationRecord private + def downcase_email! + return unless email + + self.email = email.downcase + end + def destroy_notifications # Find all notifications where user is the only reference # on the notification, and destroy all such notifications diff --git a/app/models/webhook.rb b/app/models/webhook.rb index 2388f0ebc..4fc61105f 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -6,12 +6,19 @@ class Webhook < ApplicationRecord belongs_to :activity_filter validates :http_method, presence: true validates :url, presence: true + validate :enabled? validate :valid_url scope :active, -> { where(active: true) } private + def enabled? + unless Rails.application.config.x.webhooks_enabled + errors.add(:configuration, I18n.t('activerecord.errors.models.webhook.attributes.configuration.disabled')) + end + end + def valid_url unless /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/.match?(url) errors.add(:url, I18n.t('activerecord.errors.models.webhook.attributes.url.not_valid')) diff --git a/app/permissions/organization.rb b/app/permissions/organization.rb index e702e0347..7a11acb37 100644 --- a/app/permissions/organization.rb +++ b/app/permissions/organization.rb @@ -14,7 +14,7 @@ module Organization end can :create_acitivity_filters do - true + Rails.application.config.x.webhooks_enabled end end end diff --git a/app/views/repositories/_repository_row_info_modal.html.erb b/app/views/repositories/_repository_row_info_modal.html.erb index f80c6e376..e3359f13a 100644 --- a/app/views/repositories/_repository_row_info_modal.html.erb +++ b/app/views/repositories/_repository_row_info_modal.html.erb @@ -46,7 +46,7 @@

- +
diff --git a/app/views/users/settings/account/addons/index.html.erb b/app/views/users/settings/account/addons/index.html.erb index fee31ea9b..dae490942 100644 --- a/app/views/users/settings/account/addons/index.html.erb +++ b/app/views/users/settings/account/addons/index.html.erb @@ -17,7 +17,7 @@ -
+

<%= t('users.settings.account.addons.label_printers') %>

diff --git a/config/application.rb b/config/application.rb index 2451162ff..eccd405fa 100644 --- a/config/application.rb +++ b/config/application.rb @@ -40,6 +40,8 @@ module Scinote # Max uploaded file size in MB config.x.file_max_size_mb = (ENV['FILE_MAX_SIZE_MB'] || 50).to_i + config.x.webhooks_enabled = ENV['ENABLE_WEBHOOKS'] == 'true' + # Logging config.log_formatter = proc do |severity, datetime, progname, msg| "[#{datetime}] #{severity}: #{msg}\n" diff --git a/config/locales/en.yml b/config/locales/en.yml index c97562f53..2d83bfb16 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -148,6 +148,8 @@ en: per_column_limit: "Too many items in the column" webhook: attributes: + configuration: + disabled: 'Webhooks are disabled' url: not_valid: 'Not valid URL' @@ -2727,6 +2729,7 @@ en: molecule_name_placeholder: "Click here to enter Molecule name" no_molecules_found: "No Molecules Found" save_and_register: "Save & Register to Biomolecule Toolkit" + empty_molecule_error: "An error occurred. The molecule can't be empty." marvinjs: new_sketch: "New Chemical Drawing" diff --git a/db/migrate/20210811103123_downcase_user_emails.rb b/db/migrate/20210811103123_downcase_user_emails.rb new file mode 100644 index 000000000..a6d42085f --- /dev/null +++ b/db/migrate/20210811103123_downcase_user_emails.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class DowncaseUserEmails < ActiveRecord::Migration[6.1] + def up + execute('UPDATE users SET email = LOWER(email)') + end +end diff --git a/db/structure.sql b/db/structure.sql index 68005a6a7..b98da35ce 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -7567,6 +7567,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20210715125349'), ('20210716124649'), ('20210720112050'), +('20210811103123'), ('20210812095254'), ('20210825112050'); diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 8efc7f7bd..18fc48490 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -322,6 +322,14 @@ describe User, type: :model do it { is_expected.to have_many(:system_notifications) } end + describe 'Email downcase' do + it 'downcases email before validating and saving user' do + user = User.new(email: 'Test@Email.com') + user.save + expect(user.email).to eq('test@email.com') + end + end + describe 'valid_otp?' do let(:user) { create :user } before do