2019-03-11 20:43:50 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-06-23 21:19:08 +08:00
|
|
|
class TinyMceAsset < ApplicationRecord
|
2019-04-19 20:44:40 +08:00
|
|
|
extend ProtocolsExporter
|
2019-08-09 15:47:07 +08:00
|
|
|
extend MarvinJsActions
|
2019-09-23 22:33:57 +08:00
|
|
|
include ActiveStorageConcerns
|
2023-01-20 17:45:56 +08:00
|
|
|
include Canaid::Helpers::PermissionsHelper
|
2019-09-23 22:33:57 +08:00
|
|
|
|
2017-04-21 22:09:04 +08:00
|
|
|
attr_accessor :reference
|
2019-09-12 23:21:48 +08:00
|
|
|
before_create :set_reference
|
2019-07-05 22:56:05 +08:00
|
|
|
after_create :calculate_estimated_size, :self_destruct
|
2017-04-25 19:44:31 +08:00
|
|
|
after_destroy :release_team_space
|
2017-04-21 22:09:04 +08:00
|
|
|
|
2017-06-28 21:21:32 +08:00
|
|
|
belongs_to :team, inverse_of: :tiny_mce_assets, optional: true
|
2019-03-11 20:43:50 +08:00
|
|
|
|
2019-03-20 21:40:18 +08:00
|
|
|
belongs_to :object, polymorphic: true,
|
|
|
|
optional: true,
|
|
|
|
inverse_of: :tiny_mce_assets
|
2019-07-05 22:56:05 +08:00
|
|
|
|
|
|
|
has_one_attached :image
|
|
|
|
|
2017-04-24 18:28:27 +08:00
|
|
|
validates :estimated_size, presence: true
|
|
|
|
|
2019-08-09 15:47:07 +08:00
|
|
|
def self.update_images(object, images, current_user)
|
2023-01-27 21:15:09 +08:00
|
|
|
text_field = object.public_send(Extends::RICH_TEXT_FIELD_MAPPINGS[object.class.name]) || ''
|
2023-01-12 20:24:31 +08:00
|
|
|
# image ids that are present in text
|
2023-01-27 21:15:09 +08:00
|
|
|
text_images = text_field.scan(/data-mce-token="([^"]+)"/).flatten
|
2023-01-24 18:52:20 +08:00
|
|
|
images = JSON.parse(images) + text_images
|
2023-01-12 20:24:31 +08:00
|
|
|
|
2019-03-11 20:43:50 +08:00
|
|
|
current_images = object.tiny_mce_assets.pluck(:id)
|
2019-03-20 21:40:18 +08:00
|
|
|
images_to_delete = current_images.reject do |x|
|
|
|
|
(images.include? Base62.encode(x))
|
|
|
|
end
|
2023-01-24 17:11:52 +08:00
|
|
|
|
2019-03-11 20:43:50 +08:00
|
|
|
images.each do |image|
|
2019-09-23 22:33:57 +08:00
|
|
|
image_to_update = find_by(id: Base62.decode(image))
|
2023-01-17 21:32:25 +08:00
|
|
|
|
2023-01-20 17:45:56 +08:00
|
|
|
# if image was pasted from another object, check permission and create a copy
|
|
|
|
if image_to_update.object != object && image_to_update.can_read?(current_user)
|
2023-01-24 17:11:52 +08:00
|
|
|
image_to_update.clone_tinymce_asset(object)
|
|
|
|
image_to_update.reload
|
2023-01-20 17:45:56 +08:00
|
|
|
end
|
2023-01-17 21:32:25 +08:00
|
|
|
|
2023-01-20 17:45:56 +08:00
|
|
|
next if image_to_update.object
|
2019-07-04 21:59:11 +08:00
|
|
|
|
|
|
|
image_to_update&.update(object: object, saved: true)
|
2019-08-09 15:47:07 +08:00
|
|
|
create_create_marvinjs_activity(image_to_update, current_user)
|
2019-03-11 20:43:50 +08:00
|
|
|
end
|
2019-05-20 18:44:16 +08:00
|
|
|
|
2019-09-23 22:33:57 +08:00
|
|
|
where(id: images_to_delete).find_each do |image_to_delete|
|
2019-08-09 15:47:07 +08:00
|
|
|
create_delete_marvinjs_activity(image_to_delete, current_user)
|
|
|
|
image_to_delete.destroy
|
|
|
|
end
|
2019-08-09 21:17:19 +08:00
|
|
|
|
2023-01-20 17:45:56 +08:00
|
|
|
object.delay(queue: :assets).copy_unknown_tiny_mce_images(current_user)
|
2019-03-20 21:40:18 +08:00
|
|
|
rescue StandardError => e
|
|
|
|
Rails.logger.error e.message
|
2023-01-20 17:45:56 +08:00
|
|
|
Rails.logger.error e.backtrace.join("\n")
|
2019-03-11 20:43:50 +08:00
|
|
|
end
|
|
|
|
|
2023-08-04 17:24:27 +08:00
|
|
|
def self.generate_url(description, obj = nil, is_shared_object: false)
|
2019-05-08 20:23:26 +08:00
|
|
|
# Check tinymce for old format
|
2019-05-14 21:01:57 +08:00
|
|
|
description = update_old_tinymce(description, obj)
|
2019-05-08 20:23:26 +08:00
|
|
|
|
2019-03-22 17:52:26 +08:00
|
|
|
description = Nokogiri::HTML(description)
|
2019-05-16 19:33:04 +08:00
|
|
|
tm_assets = description.css('img[data-mce-token]')
|
2023-02-17 17:36:47 +08:00
|
|
|
|
|
|
|
# Make same-page anchor links work properly with turbolinks
|
|
|
|
links = description.css('[href]')
|
|
|
|
links.each do |link|
|
|
|
|
link['data-turbolinks'] = false if link['href'].starts_with?('#')
|
|
|
|
end
|
|
|
|
|
2019-03-22 17:52:26 +08:00
|
|
|
tm_assets.each do |tm_asset|
|
2019-04-02 19:41:32 +08:00
|
|
|
asset_id = tm_asset.attr('data-mce-token')
|
2019-09-23 22:33:57 +08:00
|
|
|
new_asset = obj.tiny_mce_assets.find_by(id: Base62.decode(asset_id))
|
2019-09-30 16:25:11 +08:00
|
|
|
if new_asset&.image&.attached?
|
2023-08-04 17:24:27 +08:00
|
|
|
tm_asset.attributes['src'].value = if is_shared_object
|
|
|
|
new_asset.image.url(expires_in: Constants::URL_SHORT_EXPIRE_TIME.minutes)
|
|
|
|
else
|
|
|
|
Rails.application.routes.url_helpers.url_for(new_asset.image)
|
|
|
|
end
|
2019-03-22 17:52:26 +08:00
|
|
|
tm_asset['class'] = 'img-responsive'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
description.css('body').inner_html.to_s
|
|
|
|
end
|
|
|
|
|
2019-07-09 16:28:15 +08:00
|
|
|
def file_name
|
|
|
|
return '' unless image.attached?
|
2017-04-21 22:09:04 +08:00
|
|
|
|
2019-07-10 20:37:23 +08:00
|
|
|
image.blob&.filename&.sanitized
|
2017-04-21 22:09:04 +08:00
|
|
|
end
|
|
|
|
|
2019-07-09 16:28:15 +08:00
|
|
|
def file_size
|
|
|
|
return 0 unless image.attached?
|
|
|
|
|
|
|
|
image.blob&.byte_size
|
2017-04-21 22:09:04 +08:00
|
|
|
end
|
|
|
|
|
2019-07-09 16:28:15 +08:00
|
|
|
def content_type
|
2019-07-10 20:37:23 +08:00
|
|
|
return '' unless image.attached?
|
2017-04-21 22:09:04 +08:00
|
|
|
|
2019-07-10 20:37:23 +08:00
|
|
|
image&.blob&.content_type
|
2019-07-09 16:28:15 +08:00
|
|
|
end
|
|
|
|
|
2019-07-05 22:56:05 +08:00
|
|
|
def preview
|
2019-09-12 23:21:48 +08:00
|
|
|
image.variant(resize_to_limit: Constants::LARGE_PIC_FORMAT)
|
2017-11-21 23:30:48 +08:00
|
|
|
end
|
|
|
|
|
2019-03-20 21:40:18 +08:00
|
|
|
def self.delete_unsaved_image(id)
|
2019-09-23 22:33:57 +08:00
|
|
|
asset = find_by(id: id)
|
2019-03-20 21:40:18 +08:00
|
|
|
asset.destroy if asset && !asset.saved
|
|
|
|
end
|
2019-07-15 23:17:14 +08:00
|
|
|
|
2019-07-05 22:56:05 +08:00
|
|
|
def self.update_estimated_size(id)
|
2019-09-23 22:33:57 +08:00
|
|
|
asset = find_by(id: id)
|
2019-07-05 22:56:05 +08:00
|
|
|
return unless asset&.image&.attached?
|
2019-03-20 21:40:18 +08:00
|
|
|
|
2019-07-05 22:56:05 +08:00
|
|
|
size = asset.image.blob.byte_size
|
|
|
|
return if size.blank?
|
2017-11-21 23:30:48 +08:00
|
|
|
|
2019-07-05 22:56:05 +08:00
|
|
|
e_size = size * Constants::ASSET_ESTIMATED_SIZE_FACTOR
|
|
|
|
asset.update(estimated_size: e_size)
|
|
|
|
Rails.logger.info "Asset #{id}: Estimated size successfully calculated"
|
|
|
|
# update team space taken
|
|
|
|
asset.team.take_space(e_size)
|
|
|
|
asset.team.save
|
2019-03-20 21:40:18 +08:00
|
|
|
end
|
|
|
|
|
2020-07-24 21:25:29 +08:00
|
|
|
def self.update_old_tinymce(description, obj = nil, import = false)
|
2019-05-08 21:22:06 +08:00
|
|
|
return description unless description
|
|
|
|
|
2019-04-19 20:44:40 +08:00
|
|
|
description.scan(/\[~tiny_mce_id:(\w+)\]/).flatten.each do |token|
|
|
|
|
old_format = /\[~tiny_mce_id:#{token}\]/
|
2019-05-08 20:23:26 +08:00
|
|
|
new_format = "<img src=\"\" class=\"img-responsive\" data-mce-token=\"#{Base62.encode(token.to_i)}\"/>"
|
2019-05-14 21:01:57 +08:00
|
|
|
|
2019-09-23 22:33:57 +08:00
|
|
|
asset = find_by(id: token)
|
2019-06-14 22:20:27 +08:00
|
|
|
# impor flag only for import from file cases, because we don't have image in DB
|
|
|
|
unless asset || import
|
2019-05-15 22:11:48 +08:00
|
|
|
# remove tag if asset deleted
|
|
|
|
description.sub!(old_format, '')
|
|
|
|
next
|
|
|
|
end
|
|
|
|
|
2019-05-14 21:01:57 +08:00
|
|
|
# If object (step or result text) don't have direct assciation to tinyMCE image, we need copy it.
|
|
|
|
asset.clone_tinymce_asset(obj) if obj && obj != asset.object
|
|
|
|
|
2019-04-19 20:44:40 +08:00
|
|
|
description.sub!(old_format, new_format)
|
|
|
|
end
|
|
|
|
description
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.save_to_eln(ostream, dir)
|
|
|
|
if exists?
|
|
|
|
order(:id).each do |tiny_mce_asset|
|
|
|
|
asset_guid = get_guid(tiny_mce_asset.id)
|
2019-11-06 16:53:44 +08:00
|
|
|
extension = tiny_mce_asset.image.blob.filename.extension
|
2021-07-23 17:56:28 +08:00
|
|
|
asset_file_name = if extension.blank?
|
2019-11-06 16:53:44 +08:00
|
|
|
"rte-#{asset_guid}"
|
|
|
|
else
|
|
|
|
"rte-#{asset_guid}.#{tiny_mce_asset.image.blob.filename.extension}"
|
|
|
|
end
|
2019-04-19 20:44:40 +08:00
|
|
|
ostream.put_next_entry("#{dir}/#{asset_file_name}")
|
2019-07-09 16:28:15 +08:00
|
|
|
ostream.print(tiny_mce_asset.image.download)
|
2019-04-19 20:44:40 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
ostream
|
|
|
|
end
|
|
|
|
|
2019-05-14 21:01:57 +08:00
|
|
|
def clone_tinymce_asset(obj)
|
2023-04-04 19:42:20 +08:00
|
|
|
team_id = Team.search_by_object(obj)&.id
|
2019-05-14 21:01:57 +08:00
|
|
|
|
|
|
|
return false unless team_id
|
|
|
|
|
|
|
|
tiny_img_clone = TinyMceAsset.new(
|
|
|
|
estimated_size: estimated_size,
|
|
|
|
object: obj,
|
|
|
|
team_id: team_id
|
|
|
|
)
|
2019-07-05 22:56:05 +08:00
|
|
|
|
|
|
|
tiny_img_clone.transaction do
|
|
|
|
tiny_img_clone.save!
|
2019-08-05 17:33:49 +08:00
|
|
|
duplicate_file(tiny_img_clone)
|
2019-07-05 22:56:05 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
return false unless tiny_img_clone.persisted?
|
2019-05-14 21:01:57 +08:00
|
|
|
|
|
|
|
obj.tiny_mce_assets << tiny_img_clone
|
|
|
|
# Prepare array of image to update
|
|
|
|
cloned_img_ids = [[id, tiny_img_clone.id]]
|
|
|
|
|
|
|
|
obj_field = Extends::RICH_TEXT_FIELD_MAPPINGS[obj.class.name]
|
|
|
|
|
|
|
|
# Update description with new format
|
|
|
|
obj.update(obj_field => TinyMceAsset.update_old_tinymce(obj[obj_field]))
|
|
|
|
|
|
|
|
# reassign images
|
|
|
|
obj.reassign_tiny_mce_image_references(cloned_img_ids)
|
|
|
|
end
|
|
|
|
|
2019-08-05 17:30:36 +08:00
|
|
|
def blob
|
|
|
|
image&.blob
|
|
|
|
end
|
|
|
|
|
2024-01-23 17:16:25 +08:00
|
|
|
def convert_to_base64
|
|
|
|
encoded_data = Base64.strict_encode64(image.download)
|
|
|
|
"data:#{image.blob.content_type};base64,#{encoded_data}"
|
|
|
|
rescue StandardError => e
|
|
|
|
Rails.logger.error e.message
|
|
|
|
"data:#{image.blob.content_type};base64,"
|
|
|
|
end
|
|
|
|
|
2019-08-05 17:30:36 +08:00
|
|
|
def duplicate_file(to_asset)
|
2019-09-30 16:25:11 +08:00
|
|
|
return unless image.attached?
|
|
|
|
|
|
|
|
raise ArgumentError, 'Destination TinyMce asset should be persisted first!' unless to_asset.persisted?
|
|
|
|
|
|
|
|
image.blob.open do |tmp_file|
|
2021-01-28 21:43:45 +08:00
|
|
|
to_blob = ActiveStorage::Blob.create_and_upload!(io: tmp_file, filename: blob.filename, metadata: blob.metadata)
|
2019-09-30 16:25:11 +08:00
|
|
|
to_asset.image.attach(to_blob)
|
|
|
|
end
|
2019-08-05 17:30:36 +08:00
|
|
|
TinyMceAsset.update_estimated_size(to_asset.id)
|
2019-07-19 21:23:34 +08:00
|
|
|
end
|
|
|
|
|
2023-01-20 17:45:56 +08:00
|
|
|
def can_read?(user)
|
|
|
|
case object_type
|
|
|
|
when 'MyModule'
|
|
|
|
can_read_my_module?(user, object)
|
|
|
|
when 'Protocol'
|
|
|
|
can_read_protocol_in_module?(user, object) ||
|
|
|
|
can_read_protocol_in_repository?(user, object)
|
|
|
|
when 'ResultText'
|
|
|
|
can_read_result?(user, object.result)
|
|
|
|
when 'StepText'
|
|
|
|
protocol = object.step_orderable_element.step.protocol
|
|
|
|
can_read_protocol_in_module?(user, protocol) ||
|
|
|
|
can_read_protocol_in_repository?(user, protocol)
|
|
|
|
when 'Step'
|
|
|
|
can_read_protocol_in_module?(user, step.protocol) ||
|
|
|
|
can_read_protocol_in_repository?(user, step.protocol)
|
|
|
|
else
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-24 18:28:27 +08:00
|
|
|
private
|
|
|
|
|
2019-03-20 21:40:18 +08:00
|
|
|
def self_destruct
|
2019-09-23 22:33:57 +08:00
|
|
|
TinyMceAsset.delay(queue: :assets, run_at: 1.day.from_now).delete_unsaved_image(id)
|
2019-03-11 20:43:50 +08:00
|
|
|
end
|
|
|
|
|
2019-07-05 22:56:05 +08:00
|
|
|
def calculate_estimated_size
|
|
|
|
TinyMceAsset.delay(queue: :assets, run_at: 5.minutes.from_now).update_estimated_size(id)
|
2017-04-25 19:44:31 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def release_team_space
|
2019-03-11 20:43:50 +08:00
|
|
|
team.release_space(estimated_size)
|
|
|
|
team.save
|
2017-04-24 18:28:27 +08:00
|
|
|
end
|
|
|
|
|
2017-04-21 22:09:04 +08:00
|
|
|
def set_reference
|
|
|
|
obj_type = "#{@reference.class.to_s.underscore}=".to_sym
|
2017-04-24 22:22:25 +08:00
|
|
|
public_send(obj_type, @reference) if @reference
|
2017-04-21 22:09:04 +08:00
|
|
|
end
|
|
|
|
end
|