mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-15 17:44:46 +08:00
Move file preview generation to delayed job [SCI-3891]
This commit is contained in:
parent
29ffe05442
commit
aabeeec95a
7 changed files with 115 additions and 91 deletions
29
app/assets/javascripts/sitewide/active_storage_previews.js
Normal file
29
app/assets/javascripts/sitewide/active_storage_previews.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* eslint-disable no-unused-vars */
|
||||
|
||||
var ActiveStoragePreviews = (function() {
|
||||
const RETRY_COUNT = 50;
|
||||
const RETRY_DELAY = 5000;
|
||||
|
||||
return Object.freeze({
|
||||
reCheckPreview: function(ev) {
|
||||
var img = ev.target;
|
||||
var src = ev.target.src;
|
||||
|
||||
if (img.length === 0) return;
|
||||
|
||||
if (!img.retryCount) {
|
||||
img.retryCount = 0;
|
||||
}
|
||||
|
||||
if (img.retryCount >= RETRY_COUNT) return;
|
||||
|
||||
setTimeout(() => {
|
||||
img.src = src;
|
||||
img.retryCount += 1;
|
||||
}, RETRY_DELAY);
|
||||
},
|
||||
showPreview: function(ev) {
|
||||
$(ev.target).css('opacity', 1);
|
||||
}
|
||||
});
|
||||
}());
|
|
@ -1,17 +1,14 @@
|
|||
/* eslint no-underscore-dangle: ["error", { "allowAfterThis": true }]*/
|
||||
/* eslint no-use-before-define: ["error", { "functions": false }]*/
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
/* global Uint8Array fabric tui animateSpinner Assets
|
||||
I18n PerfectScrollbar MarvinJsEditor refreshProtocolStatusBar */
|
||||
/* global Uint8Array fabric tui animateSpinner Assets ActiveStoragePreviews
|
||||
PerfectScrollbar MarvinJsEditor refreshProtocolStatusBar */
|
||||
|
||||
|
||||
var FilePreviewModal = (function() {
|
||||
'use strict';
|
||||
|
||||
var readOnly = false;
|
||||
var CHECK_READY_DELAY = 5000;
|
||||
var CHECK_READY_TRIES_LIMIT = 60;
|
||||
var checkReadyCntr;
|
||||
|
||||
function initPreviewModal(options = {}) {
|
||||
var name;
|
||||
|
@ -30,6 +27,7 @@ var FilePreviewModal = (function() {
|
|||
});
|
||||
|
||||
$('#filePreviewModal').find('.preview-close').click(function() {
|
||||
$('#filePreviewModal').find('.file-preview-container').html('');
|
||||
$('#filePreviewModal').modal('hide');
|
||||
if (typeof refreshProtocolStatusBar === 'function') refreshProtocolStatusBar();
|
||||
});
|
||||
|
@ -477,29 +475,28 @@ var FilePreviewModal = (function() {
|
|||
link.attr('data-no-turbolink', true);
|
||||
link.attr('data-status', 'asset-present');
|
||||
if (data.type === 'image') {
|
||||
if (data.processing) {
|
||||
modal.find('.file-preview-container').append(data['processing-img']);
|
||||
} else {
|
||||
animateSpinner('.file-preview-container', false);
|
||||
modal.find('.file-preview-container')
|
||||
.append($('<img>')
|
||||
.attr('src', data['large-preview-url'])
|
||||
.attr('alt', name)
|
||||
.click(function(ev) {
|
||||
ev.stopPropagation();
|
||||
}));
|
||||
if (!readOnly && data.editable) {
|
||||
modal.find('.file-edit-link').css('display', '');
|
||||
modal.find('.file-edit-link').off().click(function(ev) {
|
||||
$.post('/files/' + data.id + '/start_edit_image');
|
||||
ev.preventDefault();
|
||||
animateSpinner('.file-preview-container', false);
|
||||
modal.find('.file-preview-container')
|
||||
.append($('<img>')
|
||||
.css('opacity', 0)
|
||||
.attr('src', data['large-preview-url'])
|
||||
.attr('alt', name)
|
||||
.on('error', ActiveStoragePreviews.reCheckPreview)
|
||||
.on('load', ActiveStoragePreviews.showPreview)
|
||||
.click(function(ev) {
|
||||
ev.stopPropagation();
|
||||
modal.modal('hide');
|
||||
preInitImageEditor(data);
|
||||
});
|
||||
} else {
|
||||
modal.find('.file-edit-link').css('display', 'none');
|
||||
}
|
||||
}));
|
||||
if (!readOnly && data.editable) {
|
||||
modal.find('.file-edit-link').css('display', '');
|
||||
modal.find('.file-edit-link').off().click(function(ev) {
|
||||
$.post('/files/' + data.id + '/start_edit_image');
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
modal.modal('hide');
|
||||
preInitImageEditor(data);
|
||||
});
|
||||
} else {
|
||||
modal.find('.file-edit-link').css('display', 'none');
|
||||
}
|
||||
} else if (data.type === 'marvinjs') {
|
||||
openMarvinEditModal(data, modal);
|
||||
|
@ -510,18 +507,12 @@ var FilePreviewModal = (function() {
|
|||
if (readOnly) {
|
||||
modal.find('#wopi_file_edit_button').remove();
|
||||
}
|
||||
if (data.processing) {
|
||||
setTimeout(function() {
|
||||
checkFileReady(url, modal);
|
||||
}, CHECK_READY_DELAY);
|
||||
}
|
||||
modal.find('.file-name').text(name);
|
||||
modal.modal();
|
||||
modal.find('a[disabled=disabled]').click(function(ev) {
|
||||
ev.preventDefault();
|
||||
});
|
||||
$('.modal-backdrop').last().css('z-index', modal.css('z-index') - 1);
|
||||
checkReadyCntr = 0;
|
||||
},
|
||||
error: function() {
|
||||
// TODO
|
||||
|
@ -529,51 +520,6 @@ var FilePreviewModal = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
function checkFileReady(url, modal) {
|
||||
$.get(url, function(data) {
|
||||
if (data.processing) {
|
||||
$('.file-download-link')
|
||||
.addClass('disabled-with-click-events')
|
||||
.attr(
|
||||
'title',
|
||||
I18n.t('general.file.processing')
|
||||
)
|
||||
.click(function(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
});
|
||||
if (checkReadyCntr < CHECK_READY_TRIES_LIMIT) {
|
||||
setTimeout(function() {
|
||||
checkFileReady(url, modal);
|
||||
}, CHECK_READY_DELAY);
|
||||
}
|
||||
} else {
|
||||
if (data.type === 'image' || (data.type === 'file' && data['preview-icon'])) {
|
||||
modal.find('.file-preview-container').empty();
|
||||
modal.find('.file-preview-container')
|
||||
.append($('<img>')
|
||||
.attr('src', data['large-preview-url'])
|
||||
.attr('alt', data.filename)
|
||||
.click(function(ev) {
|
||||
ev.stopPropagation();
|
||||
}));
|
||||
modal.find('.file-name').text(data.filename);
|
||||
modal.find('.modal-body').click(function() {
|
||||
modal.modal('hide');
|
||||
});
|
||||
modal.modal();
|
||||
$('.modal-backdrop').last().css('z-index', modal.css('z-index') - 1);
|
||||
}
|
||||
$('.file-download-link')
|
||||
.removeClass('disabled-with-click-events')
|
||||
.removeAttr('title')
|
||||
.off();
|
||||
}
|
||||
});
|
||||
|
||||
checkReadyCntr += 1;
|
||||
}
|
||||
|
||||
function clearPrevieModal() {
|
||||
var modal = $('#filePreviewModal');
|
||||
modal.find('.file-preview-container').empty();
|
||||
|
@ -584,8 +530,11 @@ var FilePreviewModal = (function() {
|
|||
function openMarvinEditModal(data, modal) {
|
||||
modal.find('.file-preview-container')
|
||||
.append($('<img>')
|
||||
.css('opacity', 0)
|
||||
.attr('src', data['large-preview-url'])
|
||||
.attr('alt', data.name)
|
||||
.on('error', ActiveStoragePreviews.reCheckPreview)
|
||||
.on('load', ActiveStoragePreviews.showPreview)
|
||||
.click(function(ev) {
|
||||
ev.stopPropagation();
|
||||
}));
|
||||
|
|
|
@ -6,8 +6,35 @@ module ActiveStorage
|
|||
include ActiveStorage::CheckBlobPermissions
|
||||
|
||||
def show
|
||||
if @blob.attachments.take.record_type == 'Asset'
|
||||
return render plain: '', status: :accepted unless preview_ready?
|
||||
end
|
||||
|
||||
expires_in ActiveStorage.service_urls_expire_in
|
||||
redirect_to @blob.representation(params[:variation_key]).processed.service_url(disposition: params[:disposition])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def preview_ready?
|
||||
processing = @blob.attachments.take.record.file_processing
|
||||
return false if processing
|
||||
|
||||
preview_exists =
|
||||
if @blob.variable?
|
||||
@blob.service.exist?(@blob.representation(params['variation_key']).key)
|
||||
else
|
||||
@blob.preview(params['variation_key']).image.attached?
|
||||
end
|
||||
|
||||
return true if preview_exists
|
||||
|
||||
unless processing
|
||||
ActiveStorage::PreviewJob.perform_later(@blob.id, params[:variation_key])
|
||||
@blob.attachments.take.record.update(file_processing: true)
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
25
app/jobs/active_storage/preview_job.rb
Normal file
25
app/jobs/active_storage/preview_job.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Provides asynchronous generation of image previews for ActiveStorage::Blob records.
|
||||
class ActiveStorage::PreviewJob < ActiveStorage::BaseJob
|
||||
queue_as :assets
|
||||
|
||||
discard_on StandardError do |job, error|
|
||||
blob = ActiveStorage::Blob.find_by(id: job.arguments.first)
|
||||
blob&.attachments&.take&.record&.update(file_processing: false)
|
||||
Rails.logger.error "Couldn't generate preview for Blob with id: #{job.arguments.first}. Error:\n #{error}"
|
||||
end
|
||||
|
||||
discard_on ActiveRecord::RecordNotFound
|
||||
|
||||
retry_on ActiveStorage::IntegrityError, attempts: 3, wait: :exponentially_longer
|
||||
|
||||
def perform(blob_id, variation_key)
|
||||
blob = ActiveStorage::Blob.find(blob_id)
|
||||
preview = blob.representation(variation_key).processed
|
||||
blob.attachments.take.record.update(file_processing: false)
|
||||
|
||||
Rails.logger.info "Preview for the Blod with id: #{blob.id} - successfully generated.\n" \
|
||||
"Transformations applied: #{preview.variation.transformations}"
|
||||
end
|
||||
end
|
|
@ -198,15 +198,11 @@ class Asset < ApplicationRecord
|
|||
end
|
||||
|
||||
def medium_preview
|
||||
return file.variant(resize_to_limit: Constants::MEDIUM_PIC_FORMAT) if previewable_image?
|
||||
|
||||
file.preview(resize_to_limit: Constants::MEDIUM_PIC_FORMAT)
|
||||
file.representation(resize_to_limit: Constants::MEDIUM_PIC_FORMAT)
|
||||
end
|
||||
|
||||
def large_preview
|
||||
return file.variant(resize_to_limit: Constants::LARGE_PIC_FORMAT) if previewable_image?
|
||||
|
||||
file.preview(resize_to_limit: Constants::LARGE_PIC_FORMAT)
|
||||
file.representation(resize_to_limit: Constants::LARGE_PIC_FORMAT)
|
||||
end
|
||||
|
||||
def file_name
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
<div class="attachment-thumbnail <%= asset.previewable? ? '' : 'no-shadow' %> <%= asset.file.attached? ? asset.file.metadata['asset_type'] : '' %>">
|
||||
<% if asset.previewable? %>
|
||||
|
||||
<%= image_tag asset.medium_preview %>
|
||||
<%= image_tag asset.medium_preview,
|
||||
onerror: 'ActiveStoragePreviews.reCheckPreview(event)',
|
||||
onload: 'ActiveStoragePreviews.showPreview(event)',
|
||||
style: 'opacity: 0' %>
|
||||
<% else %>
|
||||
<i class="fas <%= file_fa_icon_class(asset) if asset.file_name %>"></i>
|
||||
<% end %>
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
<div>
|
||||
<% if asset.previewable? %>
|
||||
<%= image_tag(asset.large_preview) %>
|
||||
<% else %>
|
||||
<i class="fas fa-10x <%= file_fa_icon_class(asset) %>"></i>
|
||||
<% end %>
|
||||
<i class="fas fa-10x <%= file_fa_icon_class(asset) %>"></i>
|
||||
<h3 class="file-name"></h3>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Reference in a new issue