Class: Export::Packagers::Documents

Inherits:
Object
  • Object
show all
Defined in:
lib/export/packagers/documents.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(query_params:, project_id:) ⇒ Documents

Returns a new instance of Documents.



10
11
12
13
14
15
# File 'lib/export/packagers/documents.rb', line 10

def initialize(query_params:, project_id:)
  @query_params = query_params
  @project_id = project_id
  @file_grouper = Export::FileGrouper.new
  @file_available_cache = {}
end

Instance Attribute Details

#project_idObject (readonly)

Returns the value of attribute project_id.



8
9
10
# File 'lib/export/packagers/documents.rb', line 8

def project_id
  @project_id
end

#query_paramsObject (readonly)

Returns the value of attribute query_params.



8
9
10
# File 'lib/export/packagers/documents.rb', line 8

def query_params
  @query_params
end

Instance Method Details

#add_manifest_row(entry, name, rows) ⇒ Object (private)



157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/export/packagers/documents.rb', line 157

def add_manifest_row(entry, name, rows)
  return unless entry.is_a?(Hash)

  document = entry[:document]
  source = entry[:source]
  rows << [
    source&.id,
    document.id,
    name,
    document.document_file_file_size.to_i
  ]
end

#document_from_entry(entry) ⇒ Object (private)



153
154
155
# File 'lib/export/packagers/documents.rb', line 153

def document_from_entry(entry)
  entry.is_a?(Hash) ? entry[:document] : entry
end

#documents_for_sources(sources) ⇒ Object (private)



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/export/packagers/documents.rb', line 75

def documents_for_sources(sources)
  documents = []
  index = 0

  sources.each do |source|
    source.documents
      .select { |document| document.project_id == project_id }
      .sort_by(&:id)
      .each do |document|
        index += 1 # 1-based for UI display
        documents << {
          source:,
          document:,
          index:
        }
      end
  end

  documents
end

#empty_previewObject (private)



185
186
187
188
189
190
# File 'lib/export/packagers/documents.rb', line 185

def empty_preview
  {
    sources: [],
    groups: []
  }
end

#file_available?(document) ⇒ Boolean

Returns:

  • (Boolean)


42
43
44
45
46
47
48
# File 'lib/export/packagers/documents.rb', line 42

def file_available?(document)
  document = document_from_entry(document)
  @file_available_cache.fetch(document.id) do
    path = document.document_file.path
    @file_available_cache[document.id] = path.present? && File.exist?(path)
  end
end

#file_path(document) ⇒ Object (private)



146
147
148
149
150
151
# File 'lib/export/packagers/documents.rb', line 146

def file_path(document)
  document = document_from_entry(document)
  path = document.document_file.path
  return path if path.present? && File.exist?(path)
  nil
end

#group_entries(documents, max_bytes) ⇒ Object (private)



100
101
102
103
104
105
106
107
108
# File 'lib/export/packagers/documents.rb', line 100

def group_entries(documents, max_bytes)
  @file_grouper.group(
    items: documents,
    max_bytes: max_bytes,
    size_extractor: ->(entry) {
      file_available?(entry[:document]) ? entry[:document].document_file_file_size.to_i : 0
    }
  )
end

#groups(max_bytes:) ⇒ Object



35
36
37
38
39
40
# File 'lib/export/packagers/documents.rb', line 35

def groups(max_bytes:)
  return [] if source_ids.empty?

  documents = unique_document_entries(documents_for_sources(sources_for_query))
  group_entries(documents, max_bytes)
end

#preview(max_bytes:) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/export/packagers/documents.rb', line 17

def preview(max_bytes:)
  return empty_preview if source_ids.empty?

  sources = sources_for_query
  table_documents = documents_for_sources(sources)
  unique_documents = unique_document_entries(table_documents)
  groups = group_entries(unique_documents, max_bytes)
  group_map = @file_grouper.build_group_map(
    groups: groups,
    id_extractor: ->(entry) { entry[:document].id }
  )

  {
    sources: serialize_sources(sources, table_documents, group_map),
    groups: serialize_groups(groups)
  }
end

#serialize_groups(groups) ⇒ Object (private)



134
135
136
137
138
139
140
141
142
143
144
# File 'lib/export/packagers/documents.rb', line 134

def serialize_groups(groups)
  groups.map.with_index do |group, index|
    available_entries = group.select { |entry| file_available?(entry[:document]) }
    {
      index:,
      size: available_entries.sum { |entry| entry[:document].document_file_file_size.to_i },
      document_ids: group.map { |entry| entry[:document].id },
      available_count: available_entries.length
    }
  end
end

#serialize_sources(sources, documents, group_map) ⇒ Object (private)



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/export/packagers/documents.rb', line 110

def serialize_sources(sources, documents, group_map)
  documents_by_source = documents.group_by { |entry| entry[:source].id }

  sources.map do |source|
    docs = documents_by_source[source.id] || []
    {
      id: source.id,
      cached: source.cached,
      documents: docs.map do |entry|
        document = entry[:document]
        {
          id: document.id,
          index: entry[:index],
          group_index: group_map[document.id],
          size: document.document_file_file_size.to_i,
          name: document.document_file_file_name,
          url: document.document_file.url(:original, false),
          available: file_available?(document)
        }
      end
    }
  end
end

#source_idsObject (private)



181
182
183
# File 'lib/export/packagers/documents.rb', line 181

def source_ids
  Array(query_params[:source_id]).flatten.compact.map(&:to_i).uniq
end

#sources_for_queryObject (private)



67
68
69
70
71
72
73
# File 'lib/export/packagers/documents.rb', line 67

def sources_for_query
  Source.joins(:project_sources)
    .where(project_sources: { project_id: project_id })
    .where(id: source_ids)
    .order(:id)
    .includes(:documents)
end

#stream(entries:, zip_streamer:, group_index:) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/export/packagers/documents.rb', line 50

def stream(entries:, zip_streamer:, group_index:)
  Export::ZipStreamer.new.stream(
    entries: entries,
    zip_streamer: zip_streamer,
    file_path: ->(entry) { file_path(document_from_entry(entry)) },
    file_name: ->(entry) { document_from_entry(entry).document_file_file_name },
    entry_id: ->(entry) { document_from_entry(entry).id },
    logger_prefix: 'Documents packager',
    on_entry: method(:add_manifest_row),
    after_stream: ->(zip, rows, written) {
      write_manifest(zip, rows, written, group_index: group_index)
    }
  )
end

#unique_document_entries(documents) ⇒ Object (private)



96
97
98
# File 'lib/export/packagers/documents.rb', line 96

def unique_document_entries(documents)
  documents.uniq { |entry| entry[:document].id }
end

#write_manifest(zip, rows, written, group_index:) ⇒ Object (private)



170
171
172
173
174
175
176
177
178
179
# File 'lib/export/packagers/documents.rb', line 170

def write_manifest(zip, rows, written, group_index:)
  return if !written || rows.empty?

  zip.write_deflated_file("documents-#{group_index + 1}.tsv") do |sink|
    sink.write("source_id\tdocument_id\tfilename\tfile_size_bytes\n")
    rows.each do |row|
      sink.write("#{row.join("\t")}\n")
    end
  end
end