mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-01-27 01:59:28 +08:00
parse smart annotations in repository export [fixes SCI-2310]
This commit is contained in:
parent
1e4a975304
commit
7d26ce561c
8 changed files with 236 additions and 10 deletions
|
@ -11,12 +11,12 @@ module RepositoryZipExport
|
|||
zip = ZipExport.create(user: current_user)
|
||||
zip.generate_exportable_zip(
|
||||
current_user,
|
||||
to_csv(ordered_rows, params[:header_ids]),
|
||||
to_csv(ordered_rows, params[:header_ids], current_user, repository.team),
|
||||
:repositories
|
||||
)
|
||||
end
|
||||
|
||||
def self.to_csv(rows, column_ids)
|
||||
def self.to_csv(rows, column_ids, user, team)
|
||||
# Parse column names
|
||||
csv_header = []
|
||||
column_ids.each do |c_id|
|
||||
|
@ -56,7 +56,11 @@ module RepositoryZipExport
|
|||
else
|
||||
cell = row.repository_cells
|
||||
.find_by(repository_column_id: c_id)
|
||||
cell ? cell.value.formatted : nil
|
||||
if cell
|
||||
SmartAnnotations::TagToText.new(
|
||||
user, team, cell.value.formatted
|
||||
).text
|
||||
end
|
||||
end
|
||||
end
|
||||
csv << csv_row
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SmartAnnotations
|
||||
class Preview
|
||||
class HtmlPreview
|
||||
class << self
|
||||
def html(name, type, object)
|
||||
send("generate_#{type}_snippet", name, object)
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'smart_annotations/permision_eval'
|
||||
require 'smart_annotations/preview'
|
||||
require 'smart_annotations/html_preview'
|
||||
|
||||
module SmartAnnotations
|
||||
class TagToHtml
|
||||
|
@ -32,7 +32,7 @@ module SmartAnnotations
|
|||
next unless object && SmartAnnotations::PermissionEval.check(user,
|
||||
type,
|
||||
object)
|
||||
SmartAnnotations::Preview.html(nil, type, object)
|
||||
SmartAnnotations::HtmlPreview.html(nil, type, object)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
next
|
||||
|
@ -42,9 +42,9 @@ module SmartAnnotations
|
|||
|
||||
def repository_item(name, user, type, object)
|
||||
if object && SmartAnnotations::PermissionEval.check(user, type, object)
|
||||
return SmartAnnotations::Preview.html(nil, type, object)
|
||||
return SmartAnnotations::HtmlPreview.html(nil, type, object)
|
||||
end
|
||||
SmartAnnotations::Preview.html(name, type, object)
|
||||
SmartAnnotations::HtmlPreview.html(name, type, object)
|
||||
end
|
||||
|
||||
def extract_values(element)
|
||||
|
|
78
app/services/smart_annotations/tag_to_text.rb
Normal file
78
app/services/smart_annotations/tag_to_text.rb
Normal file
|
@ -0,0 +1,78 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'smart_annotations/permision_eval'
|
||||
require 'smart_annotations/text_preview'
|
||||
|
||||
module SmartAnnotations
|
||||
class TagToText
|
||||
attr_reader :text
|
||||
|
||||
def initialize(user, team, text)
|
||||
parse_items_annotations(user, text)
|
||||
parse_users_annotations(user, team, @text)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
USER_REGEX = /\[\@(.*?)~([0-9a-zA-Z]+)\]/
|
||||
ITEMS_REGEX = /\[\#(.*?)~(prj|exp|tsk|rep_item)~([0-9a-zA-Z]+)\]/
|
||||
OBJECT_MAPPINGS = { prj: Project,
|
||||
exp: Experiment,
|
||||
tsk: MyModule,
|
||||
rep_item: RepositoryRow }.freeze
|
||||
|
||||
def parse_items_annotations(user, text)
|
||||
@text = text.gsub(ITEMS_REGEX) do |el|
|
||||
value = extract_values(el)
|
||||
type = value[:object_type]
|
||||
begin
|
||||
object = fetch_object(type, value[:object_id])
|
||||
# handle repository_items edge case
|
||||
if type == 'rep_item'
|
||||
repository_item(value[:name], user, type, object)
|
||||
else
|
||||
next unless object && SmartAnnotations::PermissionEval.check(user,
|
||||
type,
|
||||
object)
|
||||
SmartAnnotations::TextPreview.text(nil, type, object)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def parse_users_annotations(user, team, text)
|
||||
@text = text.gsub(USER_REGEX) do |el|
|
||||
match = el.match(USER_REGEX)
|
||||
user = User.find_by_id(match[2].base62_decode)
|
||||
next unless user
|
||||
next if UserTeam.where(user: user, team: team).empty?
|
||||
user.full_name
|
||||
end
|
||||
end
|
||||
|
||||
def repository_item(name, user, type, object)
|
||||
if object && SmartAnnotations::PermissionEval.check(user, type, object)
|
||||
return SmartAnnotations::TextPreview.text(nil, type, object)
|
||||
end
|
||||
SmartAnnotations::TextPreview.text(name, type, object)
|
||||
end
|
||||
|
||||
def extract_values(element)
|
||||
match = element.match(ITEMS_REGEX)
|
||||
{
|
||||
name: match[1],
|
||||
object_type: match[2],
|
||||
object_id: match[3].base62_decode
|
||||
}
|
||||
end
|
||||
|
||||
def fetch_object(type, id)
|
||||
klass = OBJECT_MAPPINGS.fetch(type.to_sym) do
|
||||
raise ActiveRecord::RecordNotFound.new("#{type} does not exist")
|
||||
end
|
||||
klass.find_by_id(id)
|
||||
end
|
||||
end
|
||||
end
|
43
app/services/smart_annotations/text_preview.rb
Normal file
43
app/services/smart_annotations/text_preview.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SmartAnnotations
|
||||
class TextPreview
|
||||
class << self
|
||||
def text(name, type, object)
|
||||
send("generate_#{type}_snippet", name, object)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
ROUTES = Rails.application.routes.url_helpers
|
||||
|
||||
def generate_prj_snippet(_, object)
|
||||
if object.archived?
|
||||
return "#{object.name} #{I18n.t('atwho.res.archived')}"
|
||||
end
|
||||
object.name
|
||||
end
|
||||
|
||||
def generate_exp_snippet(_, object)
|
||||
if object.archived?
|
||||
return "#{object.name} #{I18n.t('atwho.res.archived')}"
|
||||
end
|
||||
object.name
|
||||
end
|
||||
|
||||
def generate_tsk_snippet(_, object)
|
||||
if object.archived?
|
||||
return "#{object.name} #{I18n.t('atwho.res.archived')}"
|
||||
end
|
||||
object.name
|
||||
end
|
||||
|
||||
def generate_rep_item_snippet(name, object)
|
||||
if object
|
||||
return object.name
|
||||
end
|
||||
"#{name} #{I18n.t('atwho.res.deleted')}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
require 'rails_helper'
|
||||
require 'smart_annotations/preview'
|
||||
require 'smart_annotations/html_preview'
|
||||
|
||||
describe SmartAnnotations::Preview do
|
||||
describe SmartAnnotations::HtmlPreview do
|
||||
let(:subject) { described_class }
|
||||
let(:user) { create :user }
|
||||
let(:project) { create :project, name: 'my project' }
|
58
spec/services/smart_annotations/tag_to_text_spec.rb
Normal file
58
spec/services/smart_annotations/tag_to_text_spec.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe SmartAnnotations::TagToText do
|
||||
let!(:user) { create :user }
|
||||
let!(:team) { create :team }
|
||||
let!(:user_team) { create :user_team, user: user, team: team, role: 2 }
|
||||
let!(:project) { create :project, name: 'my project', team: team }
|
||||
let!(:user_project) do
|
||||
create :user_project, project: project, user: user, role: 0
|
||||
end
|
||||
let(:text) do
|
||||
"My annotation of [#my project~prj~#{project.id.base62_encode}]"
|
||||
end
|
||||
let(:subject) { described_class.new(user, team, text) }
|
||||
describe 'Parsed text' do
|
||||
it 'returns a existing string with smart annotation' do
|
||||
expect(subject.text).to eq("My annotation of #{project.name}")
|
||||
end
|
||||
end
|
||||
|
||||
describe '#extract_values/1' do
|
||||
it 'returns a parsed hash of smart annotation' do
|
||||
values = subject.send(:extract_values, '[#my project~prj~1]')
|
||||
expect(values[:name]).to eq 'my project'
|
||||
expect(values[:object_id]).to eq 1
|
||||
expect(values[:object_type]).to eq 'prj'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#fetch_object/2' do
|
||||
it 'rises an error if type is not valid' do
|
||||
expect {
|
||||
subject.send(:fetch_object, 'banana', project.id)
|
||||
}.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'returns the required object' do
|
||||
expect(subject.send(:fetch_object, 'prj', project.id)).to eq project
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parse_users_annotations/2' do
|
||||
let!(:user_two) { create :user, email: 'test_user@asdf.com' }
|
||||
let(:text) { "[@#{user.full_name}~#{user.id.base62_encode}]" }
|
||||
it 'parses the user tokent to text format' do
|
||||
expect(
|
||||
subject.send(:parse_users_annotations, user, team, text)
|
||||
).to eq user.full_name
|
||||
end
|
||||
|
||||
it 'trims the user annotation if user is not member of a team' do
|
||||
random_text = "Sec:[@#{user_two.full_name}~#{user_two.id.base62_encode}]"
|
||||
expect(
|
||||
subject.send(:parse_users_annotations, user, team, random_text)
|
||||
).to eq "Sec:"
|
||||
end
|
||||
end
|
||||
end
|
43
spec/services/smart_annotations/text_preview_spec.rb
Normal file
43
spec/services/smart_annotations/text_preview_spec.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
require 'rails_helper'
|
||||
require 'smart_annotations/text_preview'
|
||||
|
||||
describe SmartAnnotations::TextPreview do
|
||||
let(:subject) { described_class }
|
||||
let(:user) { create :user }
|
||||
let(:project) { create :project, name: 'my project' }
|
||||
let(:experiment) do
|
||||
create :experiment, name: 'my experiment',
|
||||
project: project,
|
||||
created_by: user,
|
||||
last_modified_by: user
|
||||
end
|
||||
let(:task) { create :my_module, name: 'task', experiment: experiment }
|
||||
|
||||
describe 'Project annotations' do
|
||||
it 'returns a text snippet' do
|
||||
snippet = subject.text(nil, 'prj', project)
|
||||
expect(snippet).to eq(project.name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'Experiment annotations' do
|
||||
it 'returns a text snippet' do
|
||||
snippet = subject.text(nil, 'exp', experiment)
|
||||
expect(snippet).to eq(experiment.name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'MyModule annotations' do
|
||||
it 'returns a text snippet' do
|
||||
snippet = subject.text(nil, 'tsk', task)
|
||||
expect(snippet).to eq(task.name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'Repository item annotations with type rep_item' do
|
||||
it 'returns a html snippet' do
|
||||
snippet = subject.text('my item', 'rep_item', nil)
|
||||
expect(snippet).to eq('my item (deleted)')
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue