active_list 7.2.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 884ba63410b0ba502c551bdbf9035360ad2ddefefc959de5d0b3809274e57b60
4
- data.tar.gz: 38f2ddcea9c3beb17cc6c4527152f1dba440869e4830d73d8f2c46db0b7c5f7e
3
+ metadata.gz: 493c967944f09543ead6e2782c62bbf1379d7db9ce73aaf99a31a30ae7f7ef26
4
+ data.tar.gz: 5b06ebaf0f046687c035febfd6399d86c700ab15540aa8629faf30793889dc29
5
5
  SHA512:
6
- metadata.gz: dfa9c5a61880233f0b49f883cfe340a6b63d197a2369fd6a26a079ff87f059fea98ed8ee9f4bc853a97dd6b20112de497923ab62995f642907eb3dfabfcaa877
7
- data.tar.gz: e3bf5e8a58a7ecdc81924f71476a433c03fb52b313ff304ebc8755ab13a39b7d2ea60194c669368d1139fbe37321fadbb38c854932fc46fce04d025c1e55e9e1
6
+ metadata.gz: abac2cf9a73fbb3ebcc26466e481178f4fb3645b30dbfb00dd01a807e84f6132d59b0bb3d4cd016ad9998cbc0c709c75012132f69fd9b4c434f4cb13adb7da9e
7
+ data.tar.gz: 8cf5cb483304b2da19a74b86ee1289a9d14612c640c6394f1bebed329498ddb4d2f7b9714d614db2df2813e45de7e5cebafd251cf38b988bcb0ff94ed709978f
@@ -12,12 +12,39 @@ module ActiveList
12
12
  'txt'
13
13
  end
14
14
 
15
+ def file_name_code
16
+ "file_name = #{table.model.name}.model_name.human\n".c
17
+ end
18
+
15
19
  def mime_type
16
20
  Mime::TEXT
17
21
  end
18
22
 
23
+ def generate_file_code(format)
24
+ code = file_name_code
25
+ if generator.export_class
26
+ code << generator.exportable_query_code
27
+ code << "#{generator.export_class}.perform_later(user: current_user,\n"
28
+ code << " query: query,\n"
29
+ code << " content: #{columns_to_hash},\n"
30
+ code << " file_name: file_name,\n"
31
+ code << " format: '#{format}',\n"
32
+ code << " file_extension: '#{file_extension}')\n"
33
+ code << "notify_success(:document_in_preparation)\n"
34
+ code << "redirect_to(:back)\n"
35
+ else
36
+ code << generate_data_code
37
+ code << send_data_code
38
+ end
39
+ code.c
40
+ end
41
+
19
42
  def send_data_code
20
- raise NotImplementedError, "#{self.class.name}#format_data_code is not implemented."
43
+ raise NotImplementedError.new("#{self.class.name}#send_data_code must be implemented in sub-classes.")
44
+ end
45
+
46
+ def generate_data_code
47
+ raise NotImplementedError.new("#{self.class.name}#generate_data_code must be implemented in sub-classes.")
21
48
  end
22
49
 
23
50
  def columns_headers(options = {})
@@ -46,6 +73,12 @@ module ActiveList
46
73
  end
47
74
  array
48
75
  end
76
+
77
+ def columns_to_hash
78
+ table.exportable_columns.map do |column|
79
+ [column.header_code, column.exporting_datum_code('record').to_s]
80
+ end.to_h
81
+ end
49
82
  end
50
83
  end
51
84
  end
@@ -1,6 +1,7 @@
1
1
  module ActiveList
2
2
  module Exporters
3
3
  class CsvExporter < AbstractExporter
4
+
4
5
  def file_extension
5
6
  'csv'
6
7
  end
@@ -9,7 +10,7 @@ module ActiveList
9
10
  Mime[:csv]
10
11
  end
11
12
 
12
- def send_data_code
13
+ def generate_data_code
13
14
  record = 'r'
14
15
  code = generator.select_data_code(paginate: false)
15
16
  code << "data = ::CSV.generate do |csv|\n"
@@ -18,9 +19,12 @@ module ActiveList
18
19
  code << " csv << [#{columns_to_array(:body, record: record).join(', ')}]\n"
19
20
  code << " end\n"
20
21
  code << "end\n"
21
- code << "send_data(data, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i, '_') + '.#{file_extension}')\n"
22
22
  code.c
23
23
  end
24
+
25
+ def send_data_code
26
+ "send_data(data, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: file_name.parameterize + '.#{file_extension}')\n".c
27
+ end
24
28
  end
25
29
  end
26
30
  end
@@ -4,6 +4,7 @@ Mime::Type.register('text/csv', :xcsv) unless defined? Mime::XCSV
4
4
  module ActiveList
5
5
  module Exporters
6
6
  class ExcelCsvExporter < CsvExporter
7
+
7
8
  def file_extension
8
9
  'csv'
9
10
  end
@@ -12,7 +13,7 @@ module ActiveList
12
13
  Mime[:xcsv]
13
14
  end
14
15
 
15
- def send_data_code
16
+ def generate_data_code
16
17
  record = 'r'
17
18
  code = generator.select_data_code(paginate: false)
18
19
  encoding = 'CP1252'
@@ -22,7 +23,6 @@ module ActiveList
22
23
  code << " csv << [#{columns_to_array(:body, record: record, encoding: encoding).join(', ')}]\n"
23
24
  code << " end\n"
24
25
  code << "end\n"
25
- code << "send_data(data, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_')+'.#{file_extension}')\n"
26
26
  code.c
27
27
  end
28
28
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'zip'
3
+ require 'rodf'
4
4
 
5
5
  # Register ODS format unless is already set
6
6
  Mime::Type.register('application/vnd.oasis.opendocument.spreadsheet', :ods) unless defined? Mime::ODS
@@ -8,11 +8,6 @@ Mime::Type.register('application/vnd.oasis.opendocument.spreadsheet', :ods) unle
8
8
  module ActiveList
9
9
  module Exporters
10
10
  class OpenDocumentSpreadsheetExporter < AbstractExporter
11
- DATE_ELEMENTS = {
12
- 'm' => '<number:month number:style="long"/>',
13
- 'd' => '<number:day number:style="long"/>',
14
- 'Y' => '<number:year/>'
15
- }.freeze
16
11
 
17
12
  def file_extension
18
13
  'ods'
@@ -22,55 +17,42 @@ module ActiveList
22
17
  Mime[:ods]
23
18
  end
24
19
 
25
- def send_data_code
26
- xml_escape = "to_s.gsub('&', '&amp;').gsub('\\'', '&apos;').gsub('<', '&lt;').gsub('>', '&gt;')"
27
- xml_escape << ".force_encoding('US-ASCII')" if xml_escape.respond_to?(:force_encoding)
20
+ def generate_data_code
28
21
  record = 'r'
29
- code = generator.select_data_code(paginate: false)
30
- code << "name = #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i, '_')\n"
31
- code << "file = ActiveList.temporary_directory.join(name + rand(999_999_999).to_s(36) + '.#{file_extension}')\n"
32
- code << "FileUtils.mkdir_p(file.dirname)\n"
33
- code << "Zip::OutputStream.open(file) do |zile|\n"
34
- # MimeType in first place
35
- code << " zile.put_next_entry('mimetype', nil, nil, Zip::Entry::STORED)\n"
36
- code << " zile << '#{mime_type}'\n"
37
-
38
- # Manifest
39
- code << " zile.put_next_entry('META-INF/manifest.xml')\n"
40
- code << " zile << ('<?xml version=\"1.0\" encoding=\"UTF-8\"?><manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"><manifest:file-entry manifest:media-type=\"#{mime_type}\" manifest:full-path=\"/\"/><manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/></manifest:manifest>')\n"
41
- code << " zile.put_next_entry('content.xml')\n"
42
22
 
43
- code << " zile << ('<?xml version=\"1.0\" encoding=\"UTF-8\"?><office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" xmlns:ooow=\"http://openoffice.org/2004/writer\" xmlns:oooc=\"http://openoffice.org/2004/calc\" xmlns:dom=\"http://www.w3.org/2001/xml-events\" xmlns:xforms=\"http://www.w3.org/2002/xforms\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:field=\"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0\" office:version=\"1.1\"><office:scripts/>')\n"
44
- # Styles
45
- code << " zile << ('<office:automatic-styles>"\
46
- '<style:style style:name="co1" style:family="table-column"><style:table-column-properties fo:break-before="auto" style:use-optimal-column-width="true"/></style:style>'\
47
- '<style:style style:name="header" style:family="table-cell"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style>'\
48
- '<number:date-style style:name="K4D" number:automatic-order="true"><number:text>' + ::I18n.translate('date.formats.default').gsub(/\%./) { |x| '</number:text>' + DATE_ELEMENTS[x[1..1]] + '<number:text>' } + '</number:text></number:date-style><style:style style:name="ce1" style:family="table-cell" style:data-style-name="K4D"/>'\
49
- "</office:automatic-styles>')\n"
23
+ code = generator.select_data_code(paginate: false)
24
+ code << <<~RUBY
25
+ records = #{generator.records_variable_name}
26
+ data = RODF::Spreadsheet.new
27
+
28
+ data.instance_eval do
29
+ office_style :head, family: :cell do
30
+ property :text, 'font-weight': :bold
31
+ property :paragraph, 'text-align': :center
32
+ end
33
+
34
+ table #{table.model.name}.model_name.human do
35
+ row do
36
+ #{columns_to_array(:header)}.each do |header|
37
+ cell header, style: :head
38
+ end
39
+ end
40
+
41
+ for #{record} in records
42
+ row do
43
+ #{columns_to_array(:body, record: record)}.each do |value|
44
+ cell value
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ RUBY
51
+ code.c
52
+ end
50
53
 
51
- # Tables
52
- code << " zile << ('<office:body><office:spreadsheet><table:table table:name=\"'+#{table.model.name}.model_name.human.#{xml_escape}+'\">')\n"
53
- code << " zile << ('<table:table-column table:number-columns-repeated=\"#{table.exportable_columns.size}\"/>')\n"
54
- code << " zile << ('<table:table-header-rows><table:table-row>" + columns_headers.collect { |h| "<table:table-cell table:style-name=\"header\" office:value-type=\"string\"><text:p>'+(#{h}).#{xml_escape}+'</text:p></table:table-cell>" }.join + "</table:table-row></table:table-header-rows>')\n"
55
- code << " for #{record} in #{generator.records_variable_name}\n"
56
- code << " zile << ('<table:table-row>" + table.exportable_columns.collect do |column|
57
- '<table:table-cell' + (if column.numeric? || column.datatype == :decimal
58
- " office:value-type=\"float\" office:value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
59
- elsif column.datatype == :boolean
60
- " office:value-type=\"boolean\" office:boolean-value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
61
- elsif column.datatype == :date
62
- " office:value-type=\"date\" table:style-name=\"ce1\" office:date-value=\"'+(#{column.datum_code(record)}).#{xml_escape}+'\""
63
- else
64
- ' office:value-type="string"'
65
- end) + "><text:p>'+(" + column.exporting_datum_code(record, true) + ").#{xml_escape}+'</text:p></table:table-cell>"
66
- end.join + "</table:table-row>')\n"
67
- code << " end\n"
68
- code << " zile << ('</table:table></office:spreadsheet></office:body></office:document-content>')\n"
69
- code << "end\n"
70
- code << "send_file(file, stream: false, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: name+'.#{file_extension}')\n"
71
- # code << "File.delete(file)\n" # Removes tmp files before they explode the disk
72
- # raise code
73
- code
54
+ def send_data_code
55
+ "send_data(data.bytes, type: #{mime_type.to_s.inspect}, disposition: 'inline', filename: file_name.parameterize + '.#{file_extension}')\n".c
74
56
  end
75
57
  end
76
58
  end
@@ -1,6 +1,6 @@
1
1
  module ActiveList
2
2
  class Generator
3
- attr_accessor :table, :controller, :controller_method_name, :view_method_name, :records_variable_name
3
+ attr_accessor :table, :controller, :controller_method_name, :view_method_name, :records_variable_name, :export_class
4
4
 
5
5
  def initialize(*args, &_block)
6
6
  options = args.extract_options!
@@ -12,6 +12,7 @@ module ActiveList
12
12
  @view_method_name = "_#{@controller.controller_name}_list_#{name}_tag"
13
13
  @records_variable_name = "@#{name}"
14
14
  @table = ActiveList::Definition::Table.new(name, model, options)
15
+ @export_class = options[:export_class]
15
16
  if block_given?
16
17
  yield @table
17
18
  else
@@ -47,7 +48,7 @@ module ActiveList
47
48
  code << " end\n"
48
49
  for format, exporter in ActiveList::Exporters.hash
49
50
  code << " format.#{format} do\n"
50
- code << exporter.new(self).send_data_code.dig(3)
51
+ code << exporter.new(self).generate_file_code(format).dig(3)
51
52
  code << " end\n"
52
53
  end
53
54
  code << " end\n"
@@ -64,6 +64,64 @@ module ActiveList
64
64
  code
65
65
  end
66
66
 
67
+ def exportable_query_code(options = {})
68
+ unless @table.options.keys.include?(:order)
69
+ columns = @table.table_columns
70
+ @table.options[:order] = (columns.any? ? columns.first.name.to_sym : { id: :desc })
71
+ end
72
+
73
+ class_name = "options[\"constant_name\"]&.constantize || #{@table.model.name}"
74
+ class_name = "(controller_name != '#{class_name.tableize}' && !options[\"constant_name\"] ? controller_name.to_s.classify.constantize : #{class_name})" if collection?
75
+
76
+ code = ''
77
+
78
+ code << "query = #{class_name}.to_s\n"
79
+ code << "query << #{scope_code.inspect}\n" if scope_code
80
+
81
+ if select_code
82
+ code << "select = #{select_code}\n"
83
+ code << "query << \".select(\"\n"
84
+ code << "query << select.inspect\n"
85
+ code << "query << \")\"\n"
86
+ end
87
+
88
+ if from_code
89
+ code << "from = #{from_code}\n"
90
+ code << "query << \".from(\"\n"
91
+ code << "query << from.inspect\n"
92
+ code << "query << \")\"\n"
93
+ end
94
+
95
+ unless @table.options[:conditions].blank?
96
+ code << "condition = #{conditions_code}\n"
97
+ code << "query << \".where(\"\n"
98
+ code << "query << condition.inspect\n"
99
+ code << "query << \")\"\n"
100
+ end
101
+
102
+ code << "query << \".joins(#{@table.options[:joins].inspect})\"\n" unless @table.options[:joins].blank?
103
+
104
+ unless includes_reflections.empty?
105
+ expr = includes_reflections.inspect[1..-2]
106
+ code << "query << \".includes(#{expr})\"\n"
107
+ code << "query << \".references(#{expr})\"\n"
108
+ end
109
+
110
+ unless @table.options[:group].blank?
111
+ code << "group = #{@table.options[:group].inspect}\n"
112
+ code << "query << \".group(\"\n"
113
+ code << "query << group.inspect\n"
114
+ code << "query << \")\"\n"
115
+ end
116
+
117
+ code << "order = #{var_name(:order)}\n"
118
+ code << "query << \".reorder(\"\n"
119
+ code << "query << order.inspect\n"
120
+ code << "query << \")\"\n"
121
+
122
+ code.c
123
+ end
124
+
67
125
  protected
68
126
 
69
127
  # Compute includes Hash
@@ -1,3 +1,3 @@
1
1
  module ActiveList
2
- VERSION = '7.2.0'.freeze
2
+ VERSION = '7.3.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_list
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0
4
+ version: 7.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brice Texier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-08 00:00:00.000000000 Z
11
+ date: 2020-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -86,6 +86,20 @@ dependencies:
86
86
  - - ">="
87
87
  - !ruby/object:Gem::Version
88
88
  version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rodf
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
89
103
  - !ruby/object:Gem::Dependency
90
104
  name: sqlite3
91
105
  requirement: !ruby/object:Gem::Requirement