diff --git a/app/assets/javascripts/sitewide/file_preview.js b/app/assets/javascripts/sitewide/file_preview.js index f98ebbb13..748f59296 100644 --- a/app/assets/javascripts/sitewide/file_preview.js +++ b/app/assets/javascripts/sitewide/file_preview.js @@ -595,6 +595,7 @@ var FilePreviewModal = (function() { ev.preventDefault(); ev.stopPropagation(); modal.modal('hide'); + $.post(data['update-url'] + '/start_editing'); MarvinJsEditor.open({ mode: 'edit', data: data.description, diff --git a/app/assets/javascripts/sitewide/marvinjs_editor.js b/app/assets/javascripts/sitewide/marvinjs_editor.js index 3fa9442e5..ec3f81dba 100644 --- a/app/assets/javascripts/sitewide/marvinjs_editor.js +++ b/app/assets/javascripts/sitewide/marvinjs_editor.js @@ -90,7 +90,7 @@ var MarvinJsEditorApi = (function() { sketchName.val(config.name); } else if (config.mode === 'edit-tinymce') { marvinJsRemoteLastMrv = config.data; - $.get(config.marvinUrl, { object_type: 'TinyMceAsset' }, function(result) { + $.get(config.marvinUrl, { object_type: 'TinyMceAsset', show_action: 'start_edit' }, function(result) { marvinJsRemoteEditor.importStructure('mrv', result.description); sketchName.val(result.name); }); @@ -109,7 +109,7 @@ var MarvinJsEditorApi = (function() { marvin.importStructure('mrv', config.data); sketchName.val(config.name); } else if (config.mode === 'edit-tinymce') { - $.get(config.marvinUrl, function(result) { + $.get(config.marvinUrl, { object_type: 'TinyMceAsset', show_action: 'start_edit' }, function(result) { marvin.importStructure('mrv', result.description); sketchName.val(result.name); }); diff --git a/app/controllers/concerns/marvin_js_actions.rb b/app/controllers/concerns/marvin_js_actions.rb new file mode 100644 index 000000000..5b787a876 --- /dev/null +++ b/app/controllers/concerns/marvin_js_actions.rb @@ -0,0 +1,171 @@ +# frozen_string_literal: true + +module MarvinJsActions + extend ActiveSupport::Concern + + private + + def create_edit_marvinjs_activity(asset, current_user, started_editing) + action = if started_editing == :start_editing + t('activities.file_editing.started') + elsif started_editing == :finish_editing + t('activities.file_editing.finished') + end + return unless marvinjs_asset_validation(asset) + + marvinjs_find_target_object(asset, current_user, 'edit', action) + end + + def create_create_marvinjs_activity(asset, current_user) + return unless marvinjs_asset_validation(asset) + + marvinjs_find_target_object(asset, current_user, 'create') + end + + def create_delete_marvinjs_activity(asset, current_user) + return unless marvinjs_asset_validation(asset) + + marvinjs_find_target_object(asset, current_user, 'delete') + end + + def marvinjs_asset_validation(asset) + if asset.class == Asset + asset && asset.file.metadata[:asset_type] == 'marvinjs' + else + asset && asset.image.metadata[:asset_type] == 'marvinjs' + end + end + + def marvinjs_asset_type(asset, klass) + if asset.class == Asset + return true if asset.step_asset&.step.class == klass + return true if asset.result_asset&.result.class == klass + elsif asset.object.class == klass + return true + end + false + end + + def marvinjs_find_target_object(asset, current_user, activity_type, action = nil) + if marvinjs_asset_type(asset, Step) + marvinjs_step_activity(asset, current_user, activity_type, action) + elsif marvinjs_asset_type(asset, Result) || marvinjs_asset_type(asset, ResultText) + marvinjs_result_activity(asset, current_user, activity_type, action) + elsif marvinjs_asset_type(asset, MyModule) + marvinjs_my_module_activity(asset, current_user, activity_type, action) + elsif marvinjs_asset_type(asset, Protocol) + marvinjs_protocol_activity(asset, current_user, activity_type, action) + end + end + + def marvinjs_step_activity(asset, current_user, activity, action = nil) + if asset.class == Asset + step = asset.step_asset&.step + asset_type = 'asset_name' + else + asset_type = 'tiny_mce_asset_name' + end + + protocol = step&.protocol + + return unless step && protocol + + default_step_items = + { step: step.id, + step_position: { id: step.id, value_for: 'position_plus_one' }, + asset_type => { id: asset.id, value_for: 'file_name' } } + default_step_items[:action] = action if action + if protocol.in_module? + project = protocol.my_module.experiment.project + team = project.team + type_of = (activity + '_chemical_structure_on_step').to_sym + message_items = { my_module: protocol.my_module.id } + else + type_of = (activity + '_chemical_structure_on_step_in_repository').to_sym + team = protocol.team + message_items = { protocol: protocol.id } + end + message_items = default_step_items.merge(message_items) + Activities::CreateActivityService + .call(activity_type: type_of, + owner: current_user, + subject: protocol, + team: team, + project: project, + message_items: message_items) + end + + def marvinjs_result_activity(asset, current_user, activity, action = nil) + if asset.class == Asset + result = asset.result_asset&.result + asset_type = 'asset_name' + else + result = asset.object&.result + asset_type = 'tiny_mce_asset_name' + end + + my_module = result&.my_module + + return unless result && my_module + + message_items = { + result: result.id, + asset_type => { id: asset.id, value_for: 'file_name' } + } + message_items[:action] = action if action + Activities::CreateActivityService + .call(activity_type: (activity + '_chemical_structure_on_result').to_sym, + owner: current_user, + subject: result, + team: my_module.experiment.project.team, + project: my_module.experiment.project, + message_items: message_items) + end + + def marvinjs_my_module_activity(asset, current_user, activity, action = nil) + my_module = asset.object + + return unless my_module + + message_items = { + my_module: my_module.id, + tiny_mce_asset_name: { id: asset.id, value_for: 'file_name' } + } + message_items[:action] = action if action + Activities::CreateActivityService + .call(activity_type: (activity + '_chemical_structure_on_task').to_sym, + owner: current_user, + subject: my_module, + team: my_module.experiment.project.team, + project: my_module.experiment.project, + message_items: message_items) + end + + def marvinjs_protocol_activity(asset, current_user, activity, action = nil) + protocol = asset.object + + return unless protocol + + default_step_items = + { tiny_mce_asset_name: { id: asset.id, value_for: 'file_name' } } + default_step_items[:action] = action if action + if protocol.in_module? + project = protocol.my_module.experiment.project + team = project.team + type_of = (activity + '_chemical_structure_on_task_protocol').to_sym + message_items = { my_module: protocol.my_module.id } + else + type_of = (activity + '_chemical_structure_on_protocol').to_sym + team = protocol.team + message_items = { protocol: protocol.id } + end + message_items = default_step_items.merge(message_items) + Activities::CreateActivityService + .call(activity_type: type_of, + owner: current_user, + subject: protocol, + team: team, + project: project, + message_items: message_items) + end +end diff --git a/app/controllers/marvin_js_assets_controller.rb b/app/controllers/marvin_js_assets_controller.rb index 83a7aeb56..f9b0930be 100644 --- a/app/controllers/marvin_js_assets_controller.rb +++ b/app/controllers/marvin_js_assets_controller.rb @@ -1,14 +1,19 @@ # frozen_string_literal: true class MarvinJsAssetsController < ApplicationController + include MarvinJsActions + before_action :load_vars, except: :create before_action :load_create_vars, only: :create before_action :check_read_permission - before_action :check_edit_permission, only: %i(update create) + before_action :check_edit_permission, only: %i(update create start_editing) def create result = MarvinJsService.create_sketch(marvin_params, current_user, current_team) + + create_create_marvinjs_activity(result[:asset], current_user) + if result[:asset] && marvin_params[:object_type] == 'Step' render json: { html: render_to_string( @@ -38,6 +43,9 @@ class MarvinJsAssetsController < ApplicationController def update asset = MarvinJsService.update_sketch(marvin_params, current_user, current_team) + + create_edit_marvinjs_activity(asset, current_user, :finish_editing) + if asset render json: { url: rails_representation_url(asset.medium_preview), id: asset.id, file_name: asset.file_name } else @@ -45,6 +53,10 @@ class MarvinJsAssetsController < ApplicationController end end + def start_editing + create_edit_marvinjs_activity(@asset, current_user, :start_editing) + end + private def load_vars diff --git a/app/controllers/my_modules_controller.rb b/app/controllers/my_modules_controller.rb index 63287a0da..a0b984c1c 100644 --- a/app/controllers/my_modules_controller.rb +++ b/app/controllers/my_modules_controller.rb @@ -171,7 +171,7 @@ class MyModulesController < ApplicationController if saved if description_changed log_activity(:change_module_description) - TinyMceAsset.update_images(@my_module, params[:tiny_mce_images]) + TinyMceAsset.update_images(@my_module, params[:tiny_mce_images], current_user) end if due_date_changes @@ -238,7 +238,7 @@ class MyModulesController < ApplicationController respond_to do |format| format.json do if @my_module.update(description: params.require(:my_module)[:description]) - TinyMceAsset.update_images(@my_module, params[:tiny_mce_images]) + TinyMceAsset.update_images(@my_module, params[:tiny_mce_images], current_user) render json: { html: custom_auto_link( @my_module.tinymce_render(:description), @@ -260,7 +260,7 @@ class MyModulesController < ApplicationController respond_to do |format| format.json do if protocol.update(description: params.require(:protocol)[:description]) - TinyMceAsset.update_images(protocol, params[:tiny_mce_images]) + TinyMceAsset.update_images(protocol, params[:tiny_mce_images], current_user) render json: { html: custom_auto_link( protocol.tinymce_render(:description), diff --git a/app/controllers/protocols_controller.rb b/app/controllers/protocols_controller.rb index c35cf182b..10abd9aef 100644 --- a/app/controllers/protocols_controller.rb +++ b/app/controllers/protocols_controller.rb @@ -232,7 +232,7 @@ class ProtocolsController < ApplicationController respond_to do |format| format.json do if @protocol.update(description: params.require(:protocol)[:description]) - TinyMceAsset.update_images(@protocol, params[:tiny_mce_images]) + TinyMceAsset.update_images(@protocol, params[:tiny_mce_images], current_user) render json: { html: custom_auto_link( @protocol.tinymce_render(:description), @@ -266,7 +266,7 @@ class ProtocolsController < ApplicationController log_activity(:create_protocol_in_repository, nil, protocol: @protocol.id) - TinyMceAsset.update_images(@protocol, params[:tiny_mce_images]) + TinyMceAsset.update_images(@protocol, params[:tiny_mce_images], current_user) format.json do render json: { url: edit_protocol_path( diff --git a/app/controllers/result_texts_controller.rb b/app/controllers/result_texts_controller.rb index 59cab6cbf..7d4f05e5f 100644 --- a/app/controllers/result_texts_controller.rb +++ b/app/controllers/result_texts_controller.rb @@ -42,7 +42,7 @@ class ResultTextsController < ApplicationController respond_to do |format| if @result.save && @result_text.save # link tiny_mce_assets to the text result - TinyMceAsset.update_images(@result_text, params[:tiny_mce_images]) + TinyMceAsset.update_images(@result_text, params[:tiny_mce_images], current_user) result_annotation_notification log_activity(:add_result) @@ -99,7 +99,7 @@ class ResultTextsController < ApplicationController log_activity(:archive_result) - TinyMceAsset.update_images(@result_text, params[:tiny_mce_images]) + TinyMceAsset.update_images(@result_text, params[:tiny_mce_images], current_user) end elsif @result.archived_changed?(from: true, to: false) @@ -111,7 +111,7 @@ class ResultTextsController < ApplicationController log_activity(:edit_result) - TinyMceAsset.update_images(@result_text, params[:tiny_mce_images]) + TinyMceAsset.update_images(@result_text, params[:tiny_mce_images], current_user) end end diff --git a/app/controllers/steps_controller.rb b/app/controllers/steps_controller.rb index d0fcd9040..e8c1f6198 100644 --- a/app/controllers/steps_controller.rb +++ b/app/controllers/steps_controller.rb @@ -2,6 +2,7 @@ class StepsController < ApplicationController include ActionView::Helpers::TextHelper include ApplicationHelper include StepsActions + include MarvinJsActions before_action :load_vars, only: %i(edit update destroy show toggle_step_state checklistitem_state update_view_state) before_action :load_vars_nested, only: [:new, :create] @@ -60,6 +61,10 @@ class StepsController < ApplicationController end end + + # link tiny_mce_assets to the step + TinyMceAsset.update_images(@step, params[:tiny_mce_images], current_user) + @step.save! # Post process all assets @@ -168,7 +173,7 @@ class StepsController < ApplicationController end if @step.save - TinyMceAsset.update_images(@step, params[:tiny_mce_images]) + TinyMceAsset.update_images(@step, params[:tiny_mce_images], current_user) @step.reload # generates notification on step upadate diff --git a/app/controllers/tiny_mce_assets_controller.rb b/app/controllers/tiny_mce_assets_controller.rb index 18f5f6880..c482c5c86 100644 --- a/app/controllers/tiny_mce_assets_controller.rb +++ b/app/controllers/tiny_mce_assets_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class TinyMceAssetsController < ApplicationController + include MarvinJsActions + before_action :load_vars, only: %i(marvinjs_show marvinjs_update download) before_action :check_read_permission, only: %i(marvinjs_show marvinjs_update download) @@ -41,6 +43,8 @@ class TinyMceAssetsController < ApplicationController asset = current_team.tiny_mce_assets.find_by_id(Base62.decode(params[:id])) return render_404 unless asset + create_edit_marvinjs_activity(asset, current_user, :start_editing) if params[:show_action] == 'start_edit' + render json: { name: asset.image.metadata[:name], description: asset.image.metadata[:description] @@ -65,6 +69,7 @@ class TinyMceAssetsController < ApplicationController def marvinjs_update asset = MarvinJsService.update_sketch(marvin_params, current_user, current_team) if asset + create_edit_marvinjs_activity(asset, current_user, :finish_editing) render json: { url: rails_representation_url(asset.preview), id: asset.id } else render json: { error: t('marvinjs.no_sketches_found') }, status: :unprocessable_entity diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2390d744f..24186adef 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -214,8 +214,8 @@ module ApplicationHelper end def missing_avatar(user, style) - user.avatar(style) == '/images/icon_small/missing.png' || - user.avatar(style) == '/images/thumb/missing.png' + user.avatar == '/images/icon_small/missing.png' || + user.avatar == '/images/thumb/missing.png' end def wopi_enabled? diff --git a/app/models/tiny_mce_asset.rb b/app/models/tiny_mce_asset.rb index 9d4048b7e..536166157 100644 --- a/app/models/tiny_mce_asset.rb +++ b/app/models/tiny_mce_asset.rb @@ -3,6 +3,7 @@ class TinyMceAsset < ApplicationRecord include ActiveStorage::Downloading extend ProtocolsExporter + extend MarvinJsActions attr_accessor :reference before_create :set_reference, optional: true after_create :calculate_estimated_size, :self_destruct @@ -37,7 +38,7 @@ class TinyMceAsset < ApplicationRecord # } validates :estimated_size, presence: true - def self.update_images(object, images) + def self.update_images(object, images, current_user) images = JSON.parse(images) current_images = object.tiny_mce_assets.pluck(:id) images_to_delete = current_images.reject do |x| @@ -48,9 +49,14 @@ class TinyMceAsset < ApplicationRecord next if image_to_update.object || image_to_update.team_id != Team.find_by_object(object) image_to_update&.update(object: object, saved: true) + create_create_marvinjs_activity(image_to_update, current_user) end - where(id: images_to_delete).destroy_all + where(id: images_to_delete).each do |image_to_delete| + create_delete_marvinjs_activity(image_to_delete, current_user) + image_to_delete.destroy + end + object.delay(queue: :assets).copy_unknown_tiny_mce_images rescue StandardError => e Rails.logger.error e.message diff --git a/app/services/activities/create_activity_service.rb b/app/services/activities/create_activity_service.rb index ebdcd6a22..36edf3f65 100644 --- a/app/services/activities/create_activity_service.rb +++ b/app/services/activities/create_activity_service.rb @@ -47,6 +47,9 @@ module Activities end const = try_to_constantize k + + k = k.to_s.sub('tiny_mce_asset', 'asset').to_sym if k.to_s.include? 'tiny_mce_asset' + if const if v.is_a?(Hash) # Value is array, so you have getter specified id = v[:id] diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb index b448bbf10..e99498c37 100644 --- a/config/initializers/extends.rb +++ b/config/initializers/extends.rb @@ -111,7 +111,7 @@ class Extends }.freeze ACTIVITY_MESSAGE_ITEMS_TYPES = - ACTIVITY_SUBJECT_TYPES + %w(User Tag RepositoryColumn RepositoryRow Step Asset) + ACTIVITY_SUBJECT_TYPES + %w(User Tag RepositoryColumn RepositoryRow Step Asset TinyMceAsset) .freeze ACTIVITY_TYPES = { @@ -222,18 +222,37 @@ class Extends edit_image_on_result: 110, edit_image_on_step: 111, edit_image_on_step_in_repository: 112, + edit_chemical_structure_on_step: 115, + edit_chemical_structure_on_result: 116, + edit_chemical_structure_on_step_in_repository: 117, + edit_chemical_structure_on_task_protocol: 118, + edit_chemical_structure_on_protocol: 119, + edit_chemical_structure_on_task: 120, + create_chemical_structure_on_step: 121, + create_chemical_structure_on_result: 122, + create_chemical_structure_on_step_in_repository: 123, + create_chemical_structure_on_task_protocol: 124, + create_chemical_structure_on_protocol: 125, + create_chemical_structure_on_task: 126, + delete_chemical_structure_on_step: 127, + delete_chemical_structure_on_result: 128, + delete_chemical_structure_on_step_in_repository: 129, + delete_chemical_structure_on_task_protocol: 130, + delete_chemical_structure_on_protocol: 131, + delete_chemical_structure_on_task: 132 } ACTIVITY_GROUPS = { projects: [*0..7, 32, 33, 34, 95, 108, 65, 109], - task_results: [23, 26, 25, 42, 24, 40, 41, 99, 110], - task: [8, 58, 9, 59, 10, 11, 12, 13, 14, 35, 36, 37, 53, 54, *60..64, *66..69, 106], - task_protocol: [15, 22, 16, 18, 19, 20, 21, 17, 38, 39, 100, 111, 45, 46, 47], + task_results: [23, 26, 25, 42, 24, 40, 41, 99, 110, 122, 116, 128], + task: [8, 58, 9, 59, 10, 11, 12, 13, 14, 35, 36, 37, 53, 54, *60..64, *66..69, 106, 126, 120, 132], + task_protocol: [15, 22, 16, 18, 19, 20, 21, 17, 38, 39, 100, 111, 45, 46, 47, 121, 124, 115, 118, 127, 130], task_inventory: [55, 56], experiment: [*27..31, 57], reports: [48, 50, 49], inventories: [70, 71, 105, 72, 73, 74, 102, 75, 76, 77, 78, 96, 107], - protocol_repository: [80, 103, 89, 87, 79, 90, 91, 88, 85, 86, 84, 81, 82, 83, 101, 112], + protocol_repository: [80, 103, 89, 87, 79, 90, 91, 88, 85, 86, 84, 81, 82, + 83, 101, 112, 123, 125, 117, 119, 129, 131], team: [92, 94, 93, 97, 104] }.freeze end diff --git a/config/locales/global_activities/en.yml b/config/locales/global_activities/en.yml index b2afa22be..8adab552b 100644 --- a/config/locales/global_activities/en.yml +++ b/config/locales/global_activities/en.yml @@ -134,6 +134,24 @@ en: edit_image_on_result_html: "%{user} edited image %{asset_name} on result %{result}: %{action}." edit_image_on_step_html: "%{user} edited image %{asset_name} on protocol's step %{step_position} %{step} on task %{my_module}: %{action}." edit_image_on_step_in_repository_html: "%{user} edited image %{asset_name} on protocol %{protocol}'s step %{step_position} %{step} in Protocol repository: %{action}." + edit_chemical_structure_on_step_html: "%{user} edited chemical structure %{asset_name} on protocol's step %{step_position} %{step} on task %{my_module}: %{action}." + edit_chemical_structure_on_result_html: "%{user} edited chemical structure %{asset_name} on result %{result}: %{action}." + edit_chemical_structure_on_step_in_repository_html: "%{user} edited chemical structure %{asset_name} on protocol %{protocol}'s step %{step_position} %{step}: %{action}." + edit_chemical_structure_on_task_protocol_html: "%{user} edited chemical structure %{asset_name} on task's protocol %{my_module}: %{action}." + edit_chemical_structure_on_protocol_html: "%{user} edited chemical structure %{asset_name} on protocol %{protocol}: %{action}." + edit_chemical_structure_on_task_html: "%{user} edited chemical structure %{asset_name} on task %{my_module}: %{action}." + create_chemical_structure_on_step_html: "%{user} created chemical structure %{asset_name} on protocol's step %{step_position} %{step} on task %{my_module}." + create_chemical_structure_on_result_html: "%{user} created chemical structure %{asset_name} on result %{result}." + create_chemical_structure_on_step_in_repository_html: "%{user} created chemical structure %{asset_name} on protocol %{protocol}'s step %{step_position} %{step}." + create_chemical_structure_on_task_protocol_html: "%{user} created chemical structure %{asset_name} on task's protocol %{my_module}." + create_chemical_structure_on_protocol_html: "%{user} created chemical structure %{asset_name} on protocol %{protocol}." + create_chemical_structure_on_task_html: "%{user} created chemical structure %{asset_name} on task %{my_module}." + delete_chemical_structure_on_step_html: "%{user} deleted chemical structure %{asset_name} on protocol's step %{step_position} %{step} on task %{my_module}." + delete_chemical_structure_on_result_html: "%{user} deleted chemical structure %{asset_name} on result %{result}." + delete_chemical_structure_on_step_in_repository_html: "%{user} deleted chemical structure %{asset_name} on protocol %{protocol}'s step %{step_position} %{step}." + delete_chemical_structure_on_task_protocol_html: "%{user} deleted chemical structure %{asset_name} on task's protocol %{my_module}." + delete_chemical_structure_on_protocol_html: "%{user} deleted chemical structure %{asset_name} on protocol %{protocol}." + delete_chemical_structure_on_task_html: "%{user} deleted chemical structure %{asset_name} on task %{my_module}." activity_name: create_project: "Project created" @@ -239,6 +257,24 @@ en: edit_image_on_result: "Image on result edited" edit_image_on_step: "Image on task step edited" edit_image_on_step_in_repository: "Image on step edited" + edit_chemical_structure_on_step: "Chemical structure on task step edited" + edit_chemical_structure_on_result: "Chemical structure on result edited" + edit_chemical_structure_on_step_in_repository: "Chemical structure on step edited" + edit_chemical_structure_on_task_protocol: "Chemical structure on task protocol edited" + edit_chemical_structure_on_protocol: "Chemical structure on protocol edited" + edit_chemical_structure_on_task: "Chemical structure on task edited" + create_chemical_structure_on_step: "Chemical structure on task step created" + create_chemical_structure_on_result: "Chemical structure on result created" + create_chemical_structure_on_step_in_repository: "Chemical structure on step created" + create_chemical_structure_on_task_protocol: "Chemical structure on task protocol created" + create_chemical_structure_on_protocol: "Chemical structure on protocol created" + create_chemical_structure_on_task: "Chemical structure on task created" + delete_chemical_structure_on_step: "Chemical structure on task step deleted" + delete_chemical_structure_on_result: "Chemical structure on result deleted" + delete_chemical_structure_on_step_in_repository: "Chemical structure on step deleted" + delete_chemical_structure_on_task_protocol: "Chemical structure on task protocol deleted" + delete_chemical_structure_on_protocol: "Chemical structure on protocol deleted" + delete_chemical_structure_on_task: "Chemical structure on task deleted" activity_group: projects: "Projects" diff --git a/config/routes.rb b/config/routes.rb index 4235a02d8..16449a228 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -692,6 +692,9 @@ Rails.application.routes.draw do collection do get :team_sketches end + member do + post :start_editing + end end post 'global_activities', to: 'global_activities#index'