2019-05-21 21:19:44 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
module ApplicationHelper
|
2017-01-13 18:34:10 +08:00
|
|
|
include ActionView::Helpers::AssetTagHelper
|
|
|
|
include ActionView::Helpers::UrlHelper
|
2017-05-25 22:28:06 +08:00
|
|
|
include InputSanitizeHelper
|
2017-01-13 18:34:10 +08:00
|
|
|
|
2016-07-29 21:47:41 +08:00
|
|
|
def module_page?
|
2020-04-22 23:55:22 +08:00
|
|
|
controller_name == 'my_modules' ||
|
|
|
|
controller_name == 'my_module_repositories'
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
2016-07-29 21:47:41 +08:00
|
|
|
def experiment_page?
|
|
|
|
controller_name == 'experiments'
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
2016-07-29 21:47:41 +08:00
|
|
|
def project_page?
|
2018-05-08 22:33:42 +08:00
|
|
|
controller_name == 'projects' &&
|
|
|
|
action_name.in?(%w(show experiment_archive))
|
|
|
|
end
|
|
|
|
|
|
|
|
def all_projects_page?
|
|
|
|
controller_name == 'projects' && action_name.in?(%w(index archive))
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
2016-12-14 20:36:10 +08:00
|
|
|
|
|
|
|
def display_tooltip(message, len = Constants::NAME_TRUNCATION_LENGTH)
|
2018-05-16 21:08:50 +08:00
|
|
|
return '' unless message
|
2019-05-21 21:19:44 +08:00
|
|
|
|
2017-06-19 21:30:38 +08:00
|
|
|
if message.strip.length > len
|
2017-01-03 05:27:12 +08:00
|
|
|
sanitize_input("<div class='modal-tooltip'> \
|
2023-08-21 21:59:17 +08:00
|
|
|
#{truncate(message.strip, length: len)} \
|
2017-01-03 05:27:12 +08:00
|
|
|
<span class='modal-tooltiptext'> \
|
|
|
|
#{message.strip}</span></div>")
|
2016-12-14 20:36:10 +08:00
|
|
|
else
|
2023-08-21 21:59:17 +08:00
|
|
|
truncate(message.strip, length: len)
|
2016-12-14 20:36:10 +08:00
|
|
|
end
|
|
|
|
end
|
2016-12-15 00:05:00 +08:00
|
|
|
|
2017-05-18 20:21:00 +08:00
|
|
|
def module_repository_page?
|
|
|
|
controller_name == 'my_modules' && !@repository.nil?
|
|
|
|
end
|
|
|
|
|
2021-01-12 22:26:45 +08:00
|
|
|
def displayable_flash_type?(type)
|
2021-01-20 00:19:40 +08:00
|
|
|
%w(success warning alert error notice).include?(type)
|
2021-01-12 22:26:45 +08:00
|
|
|
end
|
|
|
|
|
2021-01-04 22:11:24 +08:00
|
|
|
def flash_alert_class(type)
|
|
|
|
case type
|
|
|
|
when 'success'
|
|
|
|
'alert-success'
|
|
|
|
when 'warning'
|
|
|
|
'alert-warning'
|
2021-01-20 00:19:40 +08:00
|
|
|
when 'error', 'alert'
|
2021-01-04 22:11:24 +08:00
|
|
|
'alert-danger'
|
|
|
|
else
|
|
|
|
'alert-info'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def flash_icon_class(type)
|
|
|
|
case type
|
|
|
|
when 'error', 'warning'
|
|
|
|
'fa-exclamation-triangle'
|
|
|
|
else
|
|
|
|
'fa-check-circle'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-06 14:42:16 +08:00
|
|
|
def smart_annotation_notification(options = {})
|
|
|
|
title = options.fetch(:title) { :title_must_be_present }
|
|
|
|
message = options.fetch(:message) { :message_must_be_present }
|
|
|
|
old_text = options[:old_text] || ''
|
2023-01-27 21:15:09 +08:00
|
|
|
new_text = options[:new_text]
|
2023-11-27 18:29:27 +08:00
|
|
|
subject = options[:subject]
|
2023-01-27 21:15:09 +08:00
|
|
|
return if new_text.blank?
|
|
|
|
|
2017-04-04 15:19:43 +08:00
|
|
|
sa_user = /\[\@(.*?)~([0-9a-zA-Z]+)\]/
|
2017-04-10 17:21:28 +08:00
|
|
|
# fetch user ids from the previous text
|
2017-04-06 14:42:16 +08:00
|
|
|
old_user_ids = []
|
|
|
|
old_text.gsub(sa_user) do |el|
|
|
|
|
match = el.match(sa_user)
|
|
|
|
old_user_ids << match[2].base62_decode
|
|
|
|
end
|
2017-04-06 21:08:03 +08:00
|
|
|
# fetch user ids from the new text
|
2017-04-06 14:42:16 +08:00
|
|
|
new_user_ids = []
|
|
|
|
new_text.gsub(sa_user) do |el|
|
2017-04-04 15:19:43 +08:00
|
|
|
match = el.match(sa_user)
|
2017-04-06 14:42:16 +08:00
|
|
|
new_user_ids << match[2].base62_decode
|
2017-04-04 15:19:43 +08:00
|
|
|
end
|
2017-04-06 21:08:03 +08:00
|
|
|
# check if the user has been already mentioned
|
2017-04-06 14:42:16 +08:00
|
|
|
annotated_users = []
|
|
|
|
new_user_ids.each do |el|
|
|
|
|
annotated_users << el unless old_user_ids.include?(el)
|
|
|
|
end
|
2017-04-06 21:08:03 +08:00
|
|
|
# restrict the list of ids and generate notification
|
2017-04-04 15:19:43 +08:00
|
|
|
annotated_users.uniq.each do |user_id|
|
|
|
|
target_user = User.find_by_id(user_id)
|
|
|
|
next unless target_user
|
2019-05-21 21:19:44 +08:00
|
|
|
|
2023-11-27 18:29:27 +08:00
|
|
|
generate_annotation_notification(target_user, title, subject)
|
2017-04-04 15:19:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-11-27 18:29:27 +08:00
|
|
|
def generate_annotation_notification(target_user, title, subject)
|
|
|
|
GeneralNotification.send_notifications(
|
|
|
|
{
|
|
|
|
type: :smart_annotation_added,
|
|
|
|
title: sanitize_input(title),
|
2023-12-11 22:41:24 +08:00
|
|
|
subject_id: subject.id,
|
|
|
|
subject_class: subject.class.name,
|
|
|
|
subject_name: subject.respond_to?(:name) && subject.name,
|
2023-11-27 18:29:27 +08:00
|
|
|
user: target_user
|
|
|
|
}
|
|
|
|
)
|
2017-04-04 15:19:43 +08:00
|
|
|
end
|
|
|
|
|
2022-03-29 18:09:33 +08:00
|
|
|
def custom_link_open_new_tab(text)
|
|
|
|
text.gsub(/\<a /, '<a target=_blank ')
|
|
|
|
end
|
|
|
|
|
|
|
|
def smart_annotation_parser(text, team = nil, base64_encoded_imgs = false, preview_repository = false)
|
2017-05-03 21:30:08 +08:00
|
|
|
# sometimes happens that the "team" param gets wrong data: "{nil, []}"
|
|
|
|
# so we have to check if the "team" param is kind of Team object
|
2022-08-10 20:48:47 +08:00
|
|
|
team = nil unless team.is_a?(Team)
|
|
|
|
new_text = smart_annotation_filter_resources(text, team, preview_repository: preview_repository)
|
|
|
|
smart_annotation_filter_users(new_text, team, base64_encoded_imgs: base64_encoded_imgs)
|
2017-01-24 17:51:12 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# Check if text have smart annotations of resources
|
|
|
|
# and outputs a link to resource
|
2022-08-10 20:48:47 +08:00
|
|
|
def smart_annotation_filter_resources(text, team, preview_repository: false)
|
2019-07-01 16:14:16 +08:00
|
|
|
user = if !defined?(current_user) && @user
|
|
|
|
@user
|
|
|
|
else
|
|
|
|
current_user
|
|
|
|
end
|
2022-08-10 20:48:47 +08:00
|
|
|
team ||= defined?(current_team) ? current_team : nil
|
2023-02-21 23:53:04 +08:00
|
|
|
sanitize_input(SmartAnnotations::TagToHtml.new(user, team, text, preview_repository).html)
|
2017-01-24 17:51:12 +08:00
|
|
|
end
|
2017-01-11 00:05:32 +08:00
|
|
|
|
2017-01-24 17:51:12 +08:00
|
|
|
# Check if text have smart annotations of users
|
|
|
|
# and outputs a popover with user information
|
2022-08-10 20:48:47 +08:00
|
|
|
def smart_annotation_filter_users(text, team, base64_encoded_imgs: false)
|
2024-10-03 20:19:55 +08:00
|
|
|
text.gsub(SmartAnnotations::TagToHtml::USER_REGEX) do |el|
|
|
|
|
match = el.match(SmartAnnotations::TagToHtml::USER_REGEX)
|
|
|
|
user = User.find_by(id: match[2].base62_decode)
|
2017-05-27 00:09:29 +08:00
|
|
|
next unless user
|
2019-05-21 21:19:44 +08:00
|
|
|
|
2019-12-05 20:27:17 +08:00
|
|
|
popover_for_user_name(user, team, false, false, base64_encoded_imgs)
|
2017-01-11 00:05:32 +08:00
|
|
|
end
|
2017-01-10 00:16:39 +08:00
|
|
|
end
|
2017-04-03 21:10:00 +08:00
|
|
|
|
2017-04-04 21:22:41 +08:00
|
|
|
# Generate smart annotation link for one user object
|
2019-02-27 23:02:53 +08:00
|
|
|
def popover_for_user_name(user,
|
|
|
|
team = nil,
|
|
|
|
skip_user_status = false,
|
2019-12-05 20:27:17 +08:00
|
|
|
skip_avatar = false,
|
|
|
|
base64_encoded_imgs = false)
|
2018-11-26 22:17:18 +08:00
|
|
|
|
2023-07-18 21:59:47 +08:00
|
|
|
(defined?(controller) ? controller : ApplicationController.new)
|
2023-05-03 15:46:18 +08:00
|
|
|
.render_to_string(
|
|
|
|
partial: 'shared/atwho_user_container',
|
|
|
|
locals: {
|
|
|
|
user: user,
|
|
|
|
skip_avatar: skip_avatar,
|
|
|
|
skip_user_status: skip_user_status,
|
|
|
|
team: team,
|
2023-07-18 21:59:47 +08:00
|
|
|
base64_encoded_imgs: base64_encoded_imgs
|
2023-07-05 18:43:23 +08:00
|
|
|
},
|
|
|
|
formats: :html
|
2023-05-03 15:46:18 +08:00
|
|
|
)
|
2017-04-03 21:10:00 +08:00
|
|
|
end
|
2017-05-03 16:50:43 +08:00
|
|
|
|
2019-05-21 21:19:44 +08:00
|
|
|
# No more dirty hack
|
2019-12-05 20:27:17 +08:00
|
|
|
def user_avatar_absolute_url(user, style, base64_encoded_imgs = false)
|
2019-10-22 18:27:13 +08:00
|
|
|
avatar_link = user.avatar_variant(style)
|
|
|
|
if user.avatar.attached?
|
2019-12-05 20:27:17 +08:00
|
|
|
return user.convert_variant_to_base64(avatar_link) if base64_encoded_imgs
|
2017-06-27 17:26:32 +08:00
|
|
|
|
2023-07-12 21:42:34 +08:00
|
|
|
avatar_link.processed.url(expires_in: Constants::URL_LONG_EXPIRE_TIME)
|
2021-03-08 21:39:58 +08:00
|
|
|
elsif base64_encoded_imgs
|
|
|
|
file_path = Rails.root.join('app', 'assets', *avatar_link.split('/'))
|
|
|
|
encoded_data =
|
|
|
|
File.open(file_path) do |file|
|
|
|
|
Base64.strict_encode64(file.read)
|
|
|
|
end
|
2023-08-06 01:44:48 +08:00
|
|
|
|
|
|
|
"data:image/svg+xml;base64,#{encoded_data}"
|
2019-10-22 18:27:13 +08:00
|
|
|
else
|
|
|
|
avatar_link
|
|
|
|
end
|
2019-10-22 15:54:36 +08:00
|
|
|
rescue StandardError => e
|
|
|
|
Rails.logger.error e.message
|
2023-06-15 21:12:51 +08:00
|
|
|
'icon_small/missing.svg'
|
2017-06-27 17:26:32 +08:00
|
|
|
end
|
2019-05-10 22:25:18 +08:00
|
|
|
|
2023-02-01 22:43:20 +08:00
|
|
|
def sso_enabled?
|
|
|
|
ENV['SSO_ENABLED'] == 'true'
|
|
|
|
end
|
|
|
|
|
2024-06-27 19:54:02 +08:00
|
|
|
def sso_provider_enabled?
|
|
|
|
okta_enabled?.present? || azure_ad_enabled?.present? || saml_enabled?.present? || openid_connect_enabled?.present?
|
|
|
|
end
|
|
|
|
|
2024-04-02 20:38:21 +08:00
|
|
|
def okta_enabled?
|
|
|
|
ApplicationSettings.instance.values.dig('okta', 'enabled')
|
2023-01-31 18:55:31 +08:00
|
|
|
end
|
|
|
|
|
2024-04-02 20:38:21 +08:00
|
|
|
def azure_ad_enabled?
|
|
|
|
provider_conf = ApplicationSettings.instance.values['azure_ad_apps']
|
|
|
|
provider_conf.present? && provider_conf[0]['enabled']
|
2023-01-31 18:55:31 +08:00
|
|
|
end
|
|
|
|
|
2024-04-02 20:38:21 +08:00
|
|
|
def saml_enabled?
|
|
|
|
ApplicationSettings.instance.values.dig('saml', 'enabled')
|
2023-12-20 21:02:09 +08:00
|
|
|
end
|
|
|
|
|
2024-04-02 20:38:21 +08:00
|
|
|
def openid_connect_enabled?
|
|
|
|
ApplicationSettings.instance.values.dig('openid_connect', 'enabled')
|
2023-01-31 18:55:31 +08:00
|
|
|
end
|
|
|
|
|
2019-05-10 22:25:18 +08:00
|
|
|
def wopi_enabled?
|
|
|
|
ENV['WOPI_ENABLED'] == 'true'
|
|
|
|
end
|
2020-11-04 20:08:40 +08:00
|
|
|
|
|
|
|
# Check whether the wopi file can be edited and return appropriate response
|
|
|
|
def wopi_file_edit_button_status(asset)
|
2024-04-16 15:14:44 +08:00
|
|
|
file_ext = asset.file_name.split('.').last&.downcase
|
2020-11-04 20:08:40 +08:00
|
|
|
if Constants::WOPI_EDITABLE_FORMATS.include?(file_ext)
|
|
|
|
edit_supported = true
|
|
|
|
title = ''
|
|
|
|
else
|
|
|
|
edit_supported = false
|
|
|
|
title = if Constants::FILE_TEXT_FORMATS.include?(file_ext)
|
|
|
|
I18n.t('assets.wopi_supported_text_formats_title')
|
|
|
|
elsif Constants::FILE_TABLE_FORMATS.include?(file_ext)
|
|
|
|
I18n.t('assets.wopi_supported_table_formats_title')
|
|
|
|
else
|
|
|
|
I18n.t('assets.wopi_supported_presentation_formats_title')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return edit_supported, title
|
|
|
|
end
|
2022-12-21 18:59:25 +08:00
|
|
|
|
|
|
|
def create_2fa_qr_code(user)
|
|
|
|
user.assign_2fa_token!
|
|
|
|
qr_code_url = ROTP::TOTP.new(user.otp_secret, issuer: 'SciNote').provisioning_uri(user.email)
|
|
|
|
RQRCode::QRCode.new(qr_code_url).as_svg(module_size: 4)
|
|
|
|
end
|
2023-03-09 18:54:58 +08:00
|
|
|
|
|
|
|
def login_disclaimer
|
|
|
|
# login_disclaimer: { title: "...", body: "...", action: "..." }
|
|
|
|
ApplicationSettings.instance.values['login_disclaimer']
|
|
|
|
end
|
2023-09-29 19:49:12 +08:00
|
|
|
|
|
|
|
def show_grey_background?
|
|
|
|
return false unless controller_name && action_name
|
|
|
|
|
2023-10-03 20:24:39 +08:00
|
|
|
Extends::COLORED_BACKGROUND_ACTIONS.include?("#{controller_name}/#{action_name}")
|
2023-09-29 19:49:12 +08:00
|
|
|
end
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|