active_list 8.0.0 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c66bafe99700808007531cb050516ebd74899f3bc6da116860100a065bc86db3
4
- data.tar.gz: 76ac1ee41159a5946c0438eaef11501a1f74b97b43cd2bfcde7fa6fa818a7afb
3
+ metadata.gz: 27436c5734c9477fdef8d87ba8d8baf417a3c6a63e74dcbe6461f02236139452
4
+ data.tar.gz: 9da5f80f7bd3617a7bb71dc0266c23c943180523a7f64ffa1d522afdc08f7b5e
5
5
  SHA512:
6
- metadata.gz: 8ac35c24fac904f07c4e9a6f407312516fb2b05faf36fb31cc0592c99b6008b226fe0361edc5b13be1630e83ac5fd4273f4121918b29342d9f894b51cc7ade0e
7
- data.tar.gz: e6a686954279d6f4fd0b3780ede4e1b9d51a7601720c32dc26f7aa56be0fab31e97769c65b73cc0cd34bbf15ee0b40db227dcff9f26960a28b0124cb60eda286
6
+ metadata.gz: 6b1e434947929a963d81ad16c5fc34cae590f1010139da5862ad43aebc18f32ea946b378636c516939d7b2d0c6fa1074cf4e3a09364ebbabdbc6eef3cd85010e
7
+ data.tar.gz: e6344a3442a0c812667cd07ec35504e4545e526d4acb76bc27f02d4cbccf8205e52efccec42f8719a8f09bf25d0c3f8965ccc74b698e2a015a79f37904ccf2fc
@@ -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 = '8.0.0'.freeze
2
+ VERSION = '8.1.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: 8.0.0
4
+ version: 8.1.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-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: arel
@@ -86,6 +86,20 @@ dependencies:
86
86
  - - "<"
87
87
  - !ruby/object:Gem::Version
88
88
  version: '6'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rodf
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.1'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.1'
89
103
  - !ruby/object:Gem::Dependency
90
104
  name: rubyzip
91
105
  requirement: !ruby/object:Gem::Requirement