mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-12-10 06:06:24 +08:00
Merge branch 'develop' into features/bmt-search
This commit is contained in:
commit
ade1385392
19 changed files with 88 additions and 46 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.22.2
|
1.22.4
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
//= require repository_columns/index
|
//= require repository_columns/index
|
||||||
//= require perfect-scrollbar.min
|
//= require perfect-scrollbar.min
|
||||||
//= require shared/inline_editing
|
//= require shared/inline_editing
|
||||||
|
//= require shared/barcode_search
|
||||||
//= require activestorage
|
//= require activestorage
|
||||||
//= require global_activities/side_pane
|
//= require global_activities/side_pane
|
||||||
//= require protocols/header
|
//= require protocols/header
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,7 @@ var MyModuleRepositories = (function() {
|
||||||
var dataTableWrapper = $(tableContainer).closest('.dataTables_wrapper');
|
var dataTableWrapper = $(tableContainer).closest('.dataTables_wrapper');
|
||||||
DataTableHelpers.initLengthApearance(dataTableWrapper);
|
DataTableHelpers.initLengthApearance(dataTableWrapper);
|
||||||
DataTableHelpers.initSearchField(dataTableWrapper, I18n.t('repositories.show.filter_inventory_items'));
|
DataTableHelpers.initSearchField(dataTableWrapper, I18n.t('repositories.show.filter_inventory_items'));
|
||||||
|
$('<img class="barcode-scanner" src="/images/icon_small/barcode.png"></img>').appendTo($('.search-container'));
|
||||||
dataTableWrapper.find('.main-actions, .pagination-row').removeClass('hidden');
|
dataTableWrapper.find('.main-actions, .pagination-row').removeClass('hidden');
|
||||||
if (options.assign_mode) {
|
if (options.assign_mode) {
|
||||||
renderFullViewAssignButtons();
|
renderFullViewAssignButtons();
|
||||||
|
|
|
||||||
|
|
@ -174,27 +174,6 @@
|
||||||
|
|
||||||
$('.create-new-repository').initSubmitModal('#create-repo-modal', 'repository');
|
$('.create-new-repository').initSubmitModal('#create-repo-modal', 'repository');
|
||||||
|
|
||||||
$('.repository-show').on('click', '.barcode-scanner', function() {
|
|
||||||
var search = $('.search-container .search-field');
|
|
||||||
var input = $('<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() {
|
function initArchivingActionsInDropdown() {
|
||||||
$('.archive-repository-option').on('click', function(event) {
|
$('.archive-repository-option').on('click', function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
||||||
21
app/assets/javascripts/shared/barcode_search.js
Normal file
21
app/assets/javascripts/shared/barcode_search.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
$(document).on('click', '.barcode-scanner', function() {
|
||||||
|
var search = $('.search-container .search-field');
|
||||||
|
var input = $('<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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -92,6 +92,11 @@ var bioEddieEditor = (function() {
|
||||||
} else {
|
} else {
|
||||||
saveMolecule(svg, structure, scheduleForRegistration);
|
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.data('update-url', updateUrl);
|
||||||
bioEddieModal.find('.file-name input').val(name);
|
bioEddieModal.find('.file-name input').val(name);
|
||||||
bioEddieModal.modal('show');
|
bioEddieModal.modal('show');
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}());
|
}());
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
.main-actions {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
|
|
@ -596,3 +578,21 @@
|
||||||
max-height: 290px;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ module Users
|
||||||
return redirect_to after_omniauth_failure_path_for(resource_name)
|
return redirect_to after_omniauth_failure_path_for(resource_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
user = User.find_by(email: email)
|
user = User.find_by(email: email.downcase)
|
||||||
|
|
||||||
if user.blank?
|
if user.blank?
|
||||||
# Create new user and identity
|
# Create new user and identity
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,8 @@ class Activity < ApplicationRecord
|
||||||
breadcrumbs: {}
|
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
|
def self.activity_types_list
|
||||||
activity_list = type_ofs.map do |key, value|
|
activity_list = type_ofs.map do |key, value|
|
||||||
|
|
|
||||||
|
|
@ -293,6 +293,7 @@ class User < ApplicationRecord
|
||||||
foreign_key: :resource_owner_id,
|
foreign_key: :resource_owner_id,
|
||||||
dependent: :delete_all
|
dependent: :delete_all
|
||||||
|
|
||||||
|
before_validation :downcase_email!
|
||||||
before_destroy :destroy_notifications
|
before_destroy :destroy_notifications
|
||||||
|
|
||||||
def name
|
def name
|
||||||
|
|
@ -679,6 +680,12 @@ class User < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def downcase_email!
|
||||||
|
return unless email
|
||||||
|
|
||||||
|
self.email = email.downcase
|
||||||
|
end
|
||||||
|
|
||||||
def destroy_notifications
|
def destroy_notifications
|
||||||
# Find all notifications where user is the only reference
|
# Find all notifications where user is the only reference
|
||||||
# on the notification, and destroy all such notifications
|
# on the notification, and destroy all such notifications
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,19 @@ class Webhook < ApplicationRecord
|
||||||
belongs_to :activity_filter
|
belongs_to :activity_filter
|
||||||
validates :http_method, presence: true
|
validates :http_method, presence: true
|
||||||
validates :url, presence: true
|
validates :url, presence: true
|
||||||
|
validate :enabled?
|
||||||
validate :valid_url
|
validate :valid_url
|
||||||
|
|
||||||
scope :active, -> { where(active: true) }
|
scope :active, -> { where(active: true) }
|
||||||
|
|
||||||
private
|
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
|
def valid_url
|
||||||
unless /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/.match?(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'))
|
errors.add(:url, I18n.t('activerecord.errors.models.webhook.attributes.url.not_valid'))
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ module Organization
|
||||||
end
|
end
|
||||||
|
|
||||||
can :create_acitivity_filters do
|
can :create_acitivity_filters do
|
||||||
true
|
Rails.application.config.x.webhooks_enabled
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 bar-code-container">
|
<div class="col-md-4 bar-code-container">
|
||||||
<canvas id="bar-code-canvas" class="hidden" data-id="<%= @repository_row.parent_id || @repository_row.id %>"></canvas>
|
<canvas id="bar-code-canvas" class="hidden" data-id="<%= @repository_row.code %>"></canvas>
|
||||||
<img id="bar-code-image"></img>
|
<img id="bar-code-image"></img>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row printer-settings">
|
||||||
<div class="col-xs-12 col-sm-12">
|
<div class="col-xs-12 col-sm-12">
|
||||||
<h2 class="addons-subtitle"><%= t('users.settings.account.addons.label_printers') %></h2>
|
<h2 class="addons-subtitle"><%= t('users.settings.account.addons.label_printers') %></h2>
|
||||||
<div class="printers-container">
|
<div class="printers-container">
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ module Scinote
|
||||||
# Max uploaded file size in MB
|
# Max uploaded file size in MB
|
||||||
config.x.file_max_size_mb = (ENV['FILE_MAX_SIZE_MB'] || 50).to_i
|
config.x.file_max_size_mb = (ENV['FILE_MAX_SIZE_MB'] || 50).to_i
|
||||||
|
|
||||||
|
config.x.webhooks_enabled = ENV['ENABLE_WEBHOOKS'] == 'true'
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
config.log_formatter = proc do |severity, datetime, progname, msg|
|
config.log_formatter = proc do |severity, datetime, progname, msg|
|
||||||
"[#{datetime}] #{severity}: #{msg}\n"
|
"[#{datetime}] #{severity}: #{msg}\n"
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,8 @@ en:
|
||||||
per_column_limit: "Too many items in the column"
|
per_column_limit: "Too many items in the column"
|
||||||
webhook:
|
webhook:
|
||||||
attributes:
|
attributes:
|
||||||
|
configuration:
|
||||||
|
disabled: 'Webhooks are disabled'
|
||||||
url:
|
url:
|
||||||
not_valid: 'Not valid URL'
|
not_valid: 'Not valid URL'
|
||||||
|
|
||||||
|
|
@ -2727,6 +2729,7 @@ en:
|
||||||
molecule_name_placeholder: "Click here to enter Molecule name"
|
molecule_name_placeholder: "Click here to enter Molecule name"
|
||||||
no_molecules_found: "No Molecules Found"
|
no_molecules_found: "No Molecules Found"
|
||||||
save_and_register: "Save & Register to Biomolecule Toolkit"
|
save_and_register: "Save & Register to Biomolecule Toolkit"
|
||||||
|
empty_molecule_error: "An error occurred. The molecule can't be empty."
|
||||||
|
|
||||||
marvinjs:
|
marvinjs:
|
||||||
new_sketch: "New Chemical Drawing"
|
new_sketch: "New Chemical Drawing"
|
||||||
|
|
|
||||||
7
db/migrate/20210811103123_downcase_user_emails.rb
Normal file
7
db/migrate/20210811103123_downcase_user_emails.rb
Normal file
|
|
@ -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
|
||||||
|
|
@ -7567,6 +7567,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||||
('20210715125349'),
|
('20210715125349'),
|
||||||
('20210716124649'),
|
('20210716124649'),
|
||||||
('20210720112050'),
|
('20210720112050'),
|
||||||
|
('20210811103123'),
|
||||||
('20210812095254'),
|
('20210812095254'),
|
||||||
('20210825112050');
|
('20210825112050');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,14 @@ describe User, type: :model do
|
||||||
it { is_expected.to have_many(:system_notifications) }
|
it { is_expected.to have_many(:system_notifications) }
|
||||||
end
|
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
|
describe 'valid_otp?' do
|
||||||
let(:user) { create :user }
|
let(:user) { create :user }
|
||||||
before do
|
before do
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue