importable_attachments 0.0.13

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.
Files changed (142) hide show
  1. data/.gitignore +24 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +38 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +8 -0
  7. data/README.rdoc +3 -0
  8. data/Rakefile +29 -0
  9. data/app/assets/images/importable_attachments/.gitkeep +0 -0
  10. data/app/assets/images/importable_attachments/buttons/.htaccess +5 -0
  11. data/app/assets/images/importable_attachments/buttons/download_32.png +0 -0
  12. data/app/assets/images/importable_attachments/buttons/upload_32.png +0 -0
  13. data/app/assets/javascripts/importable_attachments/application.js +14 -0
  14. data/app/assets/javascripts/importable_attachments/attachments.coffee +41 -0
  15. data/app/assets/stylesheets/importable_attachments/application.css +14 -0
  16. data/app/assets/stylesheets/importable_attachments/attachments.css +4 -0
  17. data/app/assets/stylesheets/scaffold.css +56 -0
  18. data/app/controllers/importable_attachments/application_controller.rb +4 -0
  19. data/app/controllers/importable_attachments/attachments_controller.rb +190 -0
  20. data/app/controllers/importable_attachments/versions_controller.rb +87 -0
  21. data/app/helpers/importable_attachments/application_helper.rb +4 -0
  22. data/app/models/attachment.rb +24 -0
  23. data/app/models/importable_attachments/attachment.rb +143 -0
  24. data/app/models/importable_attachments/version.rb +50 -0
  25. data/app/validators/existing_class_validator.rb +17 -0
  26. data/app/validators/importable_attachments/csv_validator.rb +36 -0
  27. data/app/validators/importable_attachments/excel.rb +18 -0
  28. data/app/validators/importable_attachments/excel_validator.rb +18 -0
  29. data/app/views/importable_attachments/attachments/_attachment.html.haml +9 -0
  30. data/app/views/importable_attachments/attachments/_form.html.haml +22 -0
  31. data/app/views/importable_attachments/attachments/_nested_form.html.haml +20 -0
  32. data/app/views/importable_attachments/attachments/edit.html.haml +39 -0
  33. data/app/views/importable_attachments/attachments/index.html.haml +23 -0
  34. data/app/views/importable_attachments/attachments/index.xml.builder +23 -0
  35. data/app/views/importable_attachments/attachments/new.html.haml +10 -0
  36. data/app/views/importable_attachments/attachments/show.html.haml +43 -0
  37. data/app/views/importable_attachments/versions/_form.html.haml +25 -0
  38. data/app/views/importable_attachments/versions/edit.html.haml +7 -0
  39. data/app/views/importable_attachments/versions/index.html.haml +27 -0
  40. data/app/views/importable_attachments/versions/new.html.haml +5 -0
  41. data/app/views/importable_attachments/versions/show.html.haml +21 -0
  42. data/app/views/layouts/_version.html.haml +33 -0
  43. data/app/views/layouts/importable_attachments/application.html.haml +48 -0
  44. data/bin/set_lc.sh +47 -0
  45. data/config/database.yml +25 -0
  46. data/config/features/attachments.rb +8 -0
  47. data/config/features/mark_requirements.rb +3 -0
  48. data/config/features/smarter_dates.rb +3 -0
  49. data/config/features/versioning.rb +7 -0
  50. data/config/initializers/0_configuration.rb +7 -0
  51. data/config/initializers/formtastic.rb +76 -0
  52. data/config/initializers/generators.rb +10 -0
  53. data/config/initializers/paperclip.rb +27 -0
  54. data/config/locales/responders.en.yml +10 -0
  55. data/config/routes.rb +11 -0
  56. data/db/migrate/001_create_importable_attachments_versions.rb +14 -0
  57. data/db/migrate/100_create_attachments.rb +19 -0
  58. data/importable_attachments.gemspec +81 -0
  59. data/lib/generators/importable_attachments/install_generator.rb +66 -0
  60. data/lib/generators/importable_attachments/templates/features/attachments.rb.erb +7 -0
  61. data/lib/generators/importable_attachments/templates/features/versioning.rb +7 -0
  62. data/lib/generators/importable_attachments/templates/initializers/paperclip.rb +27 -0
  63. data/lib/importable_attachments/base.rb +108 -0
  64. data/lib/importable_attachments/blueprints.rb +9 -0
  65. data/lib/importable_attachments/engine.rb +8 -0
  66. data/lib/importable_attachments/importers/csv.rb +208 -0
  67. data/lib/importable_attachments/importers/excel.rb +37 -0
  68. data/lib/importable_attachments/importers.rb +7 -0
  69. data/lib/importable_attachments/version.rb +3 -0
  70. data/lib/importable_attachments.rb +9 -0
  71. data/lib/paperclip_processors/save_upload.rb +33 -0
  72. data/lib/tasks/importable_attachments_tasks.rake +4 -0
  73. data/script/rails +8 -0
  74. data/spec/attachments/books.csv +6 -0
  75. data/spec/attachments/books.txt +6 -0
  76. data/spec/attachments/books2.csv +4 -0
  77. data/spec/attachments/empty.csv +0 -0
  78. data/spec/attachments/failed_instances.csv +3 -0
  79. data/spec/attachments/invalid_headers.csv +3 -0
  80. data/spec/attachments/just_headers.csv +1 -0
  81. data/spec/attachments/mostly_empty.csv +2 -0
  82. data/spec/attachments/mostly_empty_copy.xls +0 -0
  83. data/spec/controllers/importable_attachments/attachments_controller_spec.rb +236 -0
  84. data/spec/controllers/importable_attachments/versions_controller_spec.rb +158 -0
  85. data/spec/dummy/README.rdoc +261 -0
  86. data/spec/dummy/Rakefile +7 -0
  87. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  88. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  89. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  90. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  91. data/spec/dummy/app/mailers/.gitkeep +0 -0
  92. data/spec/dummy/app/models/.gitkeep +0 -0
  93. data/spec/dummy/app/models/book.rb +13 -0
  94. data/spec/dummy/app/models/library.rb +54 -0
  95. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  96. data/spec/dummy/config/application.rb +65 -0
  97. data/spec/dummy/config/boot.rb +10 -0
  98. data/spec/dummy/config/database.yml +25 -0
  99. data/spec/dummy/config/environment.rb +5 -0
  100. data/spec/dummy/config/environments/development.rb +37 -0
  101. data/spec/dummy/config/environments/production.rb +67 -0
  102. data/spec/dummy/config/environments/test.rb +37 -0
  103. data/spec/dummy/config/initializers/0_configuration.rb +7 -0
  104. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  105. data/spec/dummy/config/initializers/inflections.rb +15 -0
  106. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  107. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  108. data/spec/dummy/config/initializers/session_store.rb +8 -0
  109. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  110. data/spec/dummy/config/locales/en.yml +5 -0
  111. data/spec/dummy/config/routes.rb +4 -0
  112. data/spec/dummy/config.ru +4 -0
  113. data/spec/dummy/db/migrate/101_create_libraries.rb +10 -0
  114. data/spec/dummy/db/migrate/102_create_books.rb +12 -0
  115. data/spec/dummy/db/schema.rb +57 -0
  116. data/spec/dummy/features/person_uploads_generic_file.feature +11 -0
  117. data/spec/dummy/features/step_definitions/person_uploads_generic_file_steps.rb +11 -0
  118. data/spec/dummy/features/step_definitions/web_steps.rb +211 -0
  119. data/spec/dummy/features/support/capybara.rb +6 -0
  120. data/spec/dummy/features/support/database_cleaner.rb +26 -0
  121. data/spec/dummy/features/support/developer_helpers.rb +47 -0
  122. data/spec/dummy/features/support/env.rb +53 -0
  123. data/spec/dummy/features/support/paths.rb +33 -0
  124. data/spec/dummy/features/support/poltergeist.rb +1 -0
  125. data/spec/dummy/features/support/selectors.rb +39 -0
  126. data/spec/dummy/features/support/transactional_fixtures.rb +14 -0
  127. data/spec/dummy/lib/assets/.gitkeep +0 -0
  128. data/spec/dummy/log/.gitkeep +0 -0
  129. data/spec/dummy/public/404.html +38 -0
  130. data/spec/dummy/public/422.html +38 -0
  131. data/spec/dummy/public/500.html +36 -0
  132. data/spec/dummy/public/favicon.ico +0 -0
  133. data/spec/dummy/script/rails +6 -0
  134. data/spec/dummy/spec/support/.gitkeep +0 -0
  135. data/spec/dummy/spec/support/paperclip.rb +1 -0
  136. data/spec/models/importable_attachments/attachment_spec.rb +177 -0
  137. data/spec/models/importable_attachments/library_spec.rb +155 -0
  138. data/spec/models/importable_attachments/version_spec.rb +25 -0
  139. data/spec/routing/importable_attachments/versions_routing_spec.rb +43 -0
  140. data/spec/spec.opts +5 -0
  141. data/spec/spec_helper.rb +30 -0
  142. metadata +737 -0
data/bin/set_lc.sh ADDED
@@ -0,0 +1,47 @@
1
+ # Pick one EVENT or SWIFTIPLY
2
+ # To run a Rails app in evented mode (eventmachine gem)
3
+ export EVENT=1
4
+
5
+ # To run in swiftiplied mode (swiftiply gem)
6
+ #export SWIFTIPLY=1
7
+
8
+ # HACK: broken locales
9
+ my_hosttype="${HOSTTYPE:='unknown_hosttype'}"
10
+ my_kernel="${OSTYPE:='unknown_kernel'}"
11
+ my_hosttype=$(uname -a)
12
+ my_kernel=$(uname -s)
13
+
14
+ if [ "${my_kernel}" != 'Darwin' ]; then
15
+ my_kernel="${my_kernel/SunOS/solaris}"
16
+ fi
17
+
18
+ # TODO: re-write my_osver detection to include major-minor-patch
19
+ my_ostype="${my_kernel/Darwin*/darwin}"
20
+ my_osver="${my_kernel/darwin/}"
21
+
22
+ if [ "${my_ostype}" != 'darwin' ]; then
23
+ my_ostype="${my_kernel/Linux*/linux}"
24
+ if [ "${my_ostype}" != 'linux' ]; then
25
+ my_ostype="${my_kernel/-gnu/}"
26
+ fi
27
+ my_osver="${my_kernel/linux-/}"
28
+ if [ ${my_ostype} != 'linux' ]; then
29
+ my_ostype="${my_kernel/solaris*/solaris}"
30
+ my_osver="${my_kernel/solaris/}"
31
+ fi
32
+ fi
33
+
34
+ case "${my_ostype}" in
35
+ 'darwin' )
36
+ LC_CTYPE='en_US.UTF-8'; builtin export LC_CTYPE
37
+ LC_ALL='en_US.UTF-8'; builtin export LC_ALL # Mnt. Lion
38
+ ;;
39
+ 'linux' )
40
+ LANG='en_US.UTF-8'; builtin export LANG
41
+ LC_ALL='en_US.UTF-8'; builtin export LC_ALL
42
+ ;;
43
+ * )
44
+ echo "Unsupported OS: ${my_ostype}"
45
+ ;;
46
+ esac
47
+
@@ -0,0 +1,25 @@
1
+ # SQLite version 3.x
2
+ # gem install sqlite3
3
+ #
4
+ # Ensure the SQLite 3 gem is defined in your Gemfile
5
+ # gem 'sqlite3'
6
+ development:
7
+ adapter: sqlite3
8
+ database: db/development.sqlite3
9
+ pool: 5
10
+ timeout: 5000
11
+
12
+ # Warning: The database defined as "test" will be erased and
13
+ # re-generated from your development database when you run "rake".
14
+ # Do not set this db to the same as development or production.
15
+ test:
16
+ adapter: sqlite3
17
+ database: ":memory:"
18
+ pool: 5
19
+ timeout: 5000
20
+
21
+ production:
22
+ adapter: sqlite3
23
+ database: db/production.sqlite3
24
+ pool: 5
25
+ timeout: 5000
@@ -0,0 +1,8 @@
1
+ Configuration.for('attachments') do
2
+ enabled true
3
+ include_revision_in_filename false
4
+ validate_on_import true
5
+ path ':rails_root/public/system/:rails_env/:style/:attachable_klass/:id_partition/:basename.:extension'
6
+ url %w(development test).include?(Rails.env) ? '/attachments/:id/download' : '/system/:rails_env/:style/:attachable_klass/:id_partition/:basename.:extension'
7
+ end
8
+
@@ -0,0 +1,3 @@
1
+ Configuration.for('mark_requirements') do
2
+ enabled true
3
+ end
@@ -0,0 +1,3 @@
1
+ Configuration.for('smarter_dates') do
2
+ enabled true
3
+ end
@@ -0,0 +1,7 @@
1
+ Configuration.for('versioning') do
2
+ enabled true
3
+ validate_item_type_constants true
4
+ path ':rails_root/public/system/:rails_env/:style/:attachable_klass/:id_partition/:basename.:stream_version.:extension'
5
+ url %w(development test).include?(Rails.env) ? '/attachments/:id/download' : '/system/:rails_env/:style/:attachable_klass/:id_partition/:basename.:stream_version.:extension'
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ Configuration.path = 'config/features'
2
+
3
+ # load feature configurations
4
+ features = Configuration.path.collect { |path| Dir.glob(File.join(path, '**')) }.flatten
5
+ features.each do |feature|
6
+ Configuration.load feature
7
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+
3
+ # Set the default text field size when input is a string. Default is nil.
4
+ # Formtastic::FormBuilder.default_text_field_size = 50
5
+
6
+ # Set the default text area height when input is a text. Default is 20.
7
+ # Formtastic::FormBuilder.default_text_area_height = 5
8
+
9
+ # Set the default text area width when input is a text. Default is nil.
10
+ # Formtastic::FormBuilder.default_text_area_width = 50
11
+
12
+ # Should all fields be considered "required" by default?
13
+ # Defaults to true.
14
+ # Formtastic::FormBuilder.all_fields_required_by_default = true
15
+
16
+ # Should select fields have a blank option/prompt by default?
17
+ # Defaults to true.
18
+ # Formtastic::FormBuilder.include_blank_for_select_by_default = true
19
+
20
+ # Set the string that will be appended to the labels/fieldsets which are required
21
+ # It accepts string or procs and the default is a localized version of
22
+ # '<abbr title="required">*</abbr>'. In other words, if you configure formtastic.required
23
+ # in your locale, it will replace the abbr title properly. But if you don't want to use
24
+ # abbr tag, you can simply give a string as below
25
+ # Formtastic::FormBuilder.required_string = "(required)"
26
+
27
+ # Set the string that will be appended to the labels/fieldsets which are optional
28
+ # Defaults to an empty string ("") and also accepts procs (see required_string above)
29
+ # Formtastic::FormBuilder.optional_string = "(optional)"
30
+
31
+ # Set the way inline errors will be displayed.
32
+ # Defaults to :sentence, valid options are :sentence, :list, :first and :none
33
+ # Formtastic::FormBuilder.inline_errors = :sentence
34
+ # Formtastic uses the following classes as default for hints, inline_errors and error list
35
+
36
+ # If you override the class here, please ensure to override it in your stylesheets as well
37
+ # Formtastic::FormBuilder.default_hint_class = "inline-hints"
38
+ # Formtastic::FormBuilder.default_inline_error_class = "inline-errors"
39
+ # Formtastic::FormBuilder.default_error_list_class = "errors"
40
+
41
+ # Set the method to call on label text to transform or format it for human-friendly
42
+ # reading when formtastic is used without object. Defaults to :humanize.
43
+ # Formtastic::FormBuilder.label_str_method = :humanize
44
+
45
+ # Set the array of methods to try calling on parent objects in :select and :radio inputs
46
+ # for the text inside each @<option>@ tag or alongside each radio @<input>@. The first method
47
+ # that is found on the object will be used.
48
+ # Defaults to ["to_label", "display_name", "full_name", "name", "title", "username", "login", "value", "to_s"]
49
+ # Formtastic::FormBuilder.collection_label_methods = [
50
+ # "to_label", "display_name", "full_name", "name", "title", "username", "login", "value", "to_s"]
51
+
52
+ # Specifies if labels/hints for input fields automatically be looked up using I18n.
53
+ # Default value: true. Overridden for specific fields by setting value to true,
54
+ # i.e. :label => true, or :hint => true (or opposite depending on initialized value)
55
+ # Formtastic::FormBuilder.i18n_lookups_by_default = false
56
+
57
+ # Specifies if I18n lookups of the default I18n Localizer should be cached to improve performance.
58
+ # Defaults to true.
59
+ # Formtastic::FormBuilder.i18n_cache_lookups = false
60
+
61
+ # Specifies the class to use for localization lookups. You can create your own
62
+ # class and use it instead by subclassing Formtastic::Localizer (which is the default).
63
+ # Formtastic::FormBuilder.i18n_localizer = MyOwnLocalizer
64
+
65
+ # You can add custom inputs or override parts of Formtastic by subclassing Formtastic::FormBuilder and
66
+ # specifying that class here. Defaults to Formtastic::FormBuilder.
67
+ # Formtastic::Helpers::FormHelper.builder = MyCustomBuilder
68
+
69
+ # You can opt-in to Formtastic's use of the HTML5 `required` attribute on `<input>`, `<select>`
70
+ # and `<textarea>` tags by setting this to false (defaults to true).
71
+ # Formtastic::FormBuilder.use_required_attribute = true
72
+
73
+ # You can opt-in to new HTML5 browser validations (for things like email and url inputs) by setting
74
+ # this to false. Doing so will add a `novalidate` attribute to the `<form>` tag.
75
+ # See http://diveintohtml5.org/forms.html#validation for more info.
76
+ # Formtastic::FormBuilder.perform_browser_validations = true
@@ -0,0 +1,10 @@
1
+ Rails.application.config.generators do |g|
2
+ g.view_specs false
3
+ g.helper_specs false
4
+ g.test_framework :rspec
5
+ g.fixture_replacement :machinist
6
+ g.orm :active_record
7
+ g.template_engine :haml
8
+ g.stylesheet_engine :sass
9
+ end
10
+
@@ -0,0 +1,27 @@
1
+ Paperclip.interpolates :stream_version do |attachment, _|
2
+ attachment.instance.revision_number
3
+ end
4
+
5
+ Paperclip.interpolates :attachable_klass do |attachment, _|
6
+ attachable_type = attachment.instance.attachable_type
7
+ attachable_type && attachable_type.respond_to?(:tableize) ? attachable_type.tableize : '.'
8
+ end
9
+
10
+ Paperclip.interpolates :rails_env do |_, _|
11
+ Rails.env
12
+ end
13
+
14
+ # brew on darwin
15
+ if File.directory?(File.join("", 'usr', 'local', 'bin'))
16
+ Paperclip.options[:command_path] = '/usr/local/bin'
17
+
18
+ # macports on darwin
19
+ elsif File.directory?(File.join("", 'opt', 'local', 'bin'))
20
+ Paperclip.options[:command_path] = '/opt/local/bin'
21
+
22
+ # "disabled" macports due to brew on darwin
23
+ elsif File.directory?(File.join("", 'opt', 'local.brew', 'bin'))
24
+ Paperclip.options[:command_path] = '/opt/local.brew/bin'
25
+ else
26
+ raise RuntimeError, 'can not locate identify binary'
27
+ end
@@ -0,0 +1,10 @@
1
+ en:
2
+ flash:
3
+ actions:
4
+ create:
5
+ notice: '%{resource_name} was successfully created.'
6
+ update:
7
+ notice: '%{resource_name} was successfully updated.'
8
+ destroy:
9
+ notice: '%{resource_name} was successfully destroyed.'
10
+ alert: '%{resource_name} could not be destroyed.'
data/config/routes.rb ADDED
@@ -0,0 +1,11 @@
1
+ ImportableAttachments::Engine.routes.draw do
2
+ root to: 'attachments#index'
3
+ resources :versions
4
+ resources :attachments
5
+ match 'attachments/:id/download', action: :download, via: :get
6
+ end
7
+
8
+ Rails.application.routes.draw do
9
+ resources :attachments, controller: 'importable_attachments/attachments'
10
+ match 'attachments/:id/download', controller: 'importable_attachments/attachments', action: :download, via: :get
11
+ end
@@ -0,0 +1,14 @@
1
+ class CreateImportableAttachmentsVersions < ActiveRecord::Migration
2
+ def change
3
+ create_table :importable_attachments_versions, force: true do |t|
4
+ t.string :item_type, null: false
5
+ t.string :item_id, null: false # item_type.id generally should be GUID
6
+ t.string :event, null: false
7
+ t.string :whodunnit
8
+ t.text :object
9
+ t.datetime :created_at
10
+ end
11
+ add_index :importable_attachments_versions, [:item_type, :item_id]
12
+ end
13
+ end
14
+
@@ -0,0 +1,19 @@
1
+ class CreateAttachments < ActiveRecord::Migration
2
+
3
+ # Store application specific data for attachments a.k.a. uploaded files
4
+ def change
5
+ create_table :importable_attachments_attachments, :force => true do |t|
6
+ t.string :attachable_type
7
+ t.string :attachable_id # project might be using alpha-numeric IDs
8
+ t.string :io_stream_file_name
9
+ t.string :io_stream_content_type
10
+ t.integer :io_stream_file_size, :limit => 8
11
+ t.datetime :io_stream_updated_at
12
+
13
+ t.timestamps
14
+ end
15
+ add_index :importable_attachments_attachments, [:attachable_type, :attachable_id], name: 'idx_importable_attachments_on_attachable_type_and_id'
16
+ add_index :importable_attachments_attachments, :io_stream_file_name
17
+ end
18
+ end
19
+
@@ -0,0 +1,81 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'importable_attachments/version'
6
+ #Bundler.require(:default, :development)
7
+
8
+ REQUIREMENTS = {
9
+ runtime: {
10
+ :'haml-rails' => ['~> 0.4'],
11
+ paper_trail: ['~> 2.7.1'],
12
+ paperclip: ['~> 3.4.2'],
13
+ configuration: ['~> 1.3.2'],
14
+ smarter_dates: ['~> 0.2.12'],
15
+ :'ruby-filemagic' => ['~> 0.4.2'],
16
+ :'rspec-paper_trail' => ['~> 0.0.10'],
17
+ :'rails-mark_requirements' => ['~> 0.0.1'],
18
+ :'rails-alpha_numeric_validator' => ['~> 0.1.1'],
19
+ formtastic: ['~> 2.2.1'],
20
+ remotipart: ['~> 1.0.5'],
21
+ roo: ['~> 1.11.2'],
22
+ rails: ['~> 3.2.13'],
23
+ :'activerecord-import' => ['~> 0.3.1'],
24
+ :'coffee-script' => ['~> 2.2.0'],
25
+ :'coffee-rails' => ['~> 3.2.2'] }, # coffee-rails is needed for <= 3.0.x
26
+ development: {
27
+ bundler: ['~> 1.3.0'],
28
+ rake: ['>= 0'],
29
+ sqlite3: ['~> 1.3.7'],
30
+ debugger: ['~> 1.5.0'],
31
+ rspec: ['~> 2.13.0'],
32
+ mocha: ['~> 0.13.0'],
33
+ database_cleaner: ['~> 1.0.1'],
34
+ machinist: ['~> 2.0.0'],
35
+ :'rspec-rails' => ['~> 2.13.0'],
36
+ :'cucumber-rails' => ['~> 1.3.1'],
37
+ poltergeist: ['< 1.1.0'],
38
+ capybara: ['< 2.0.0'],
39
+ launchy: ['~> 2.3.0'],
40
+ valid_attribute: ['~> 1.3.1'] }
41
+ }
42
+
43
+ Gem::Specification.new do |spec|
44
+ spec.name = 'importable_attachments'
45
+ spec.version = ImportableAttachments::VERSION
46
+ spec.authors = ['Paul Belt']
47
+ spec.email = %w(saprb@channing.harvard.edu)
48
+ spec.description = %q{Easier upload management for ActiveRecord}
49
+ spec.summary = %q{upload, save-to-disk, attach-to-model_instance, importing}
50
+ spec.homepage = 'https://github.com/belt/importable_attachments'
51
+ spec.license = 'MIT'
52
+
53
+ spec.files = `git ls-files`.split($/)
54
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
55
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
56
+ spec.require_paths = %w(lib)
57
+
58
+ spec.requirements = %w(libmagic)
59
+ spec.required_ruby_version = Gem::Requirement.new('>= 1.9.2')
60
+ spec.required_rubygems_version = Gem::Requirement.new('>= 0') if spec.respond_to? :required_rubygems_version=
61
+
62
+ [:runtime, :development].each do |mode|
63
+ REQUIREMENTS[mode].each do |req,ver|
64
+ if spec.respond_to? :specification_version
65
+ spec.specification_version = 3
66
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0')
67
+ if mode == :runtime
68
+ spec.add_runtime_dependency req.to_s, ver
69
+ else
70
+ spec.add_development_dependency req.to_s, ver
71
+ end
72
+ else
73
+ spec.add_dependency req.to_s, ver
74
+ end
75
+ else
76
+ spec.add_dependency req.to_s, ver
77
+ end
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,66 @@
1
+ require 'rails/generators/active_record/migration'
2
+
3
+ # :nodoc:
4
+ module ImportableAttachments
5
+ # copies configuration file for configuration.gem
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ extend ActiveRecord::Generators::Migration
9
+
10
+ source_root File.expand_path('../templates', __FILE__)
11
+ class_option :with_string_ids, type: :boolean, default: true, desc: 'versions.type_id as string (vs integer)'
12
+
13
+ # paperclip-3.3.x seems to require this
14
+ # paperclip-3.4.x seems to have broken this
15
+ class_option :with_revision_in_filename, type: :boolean, default: false, desc: 'filename on system to include version-number'
16
+
17
+ class_option :'skip-migrations', type: :boolean, default: false, desc: 'do not generate migrations'
18
+ class_option :force, type: :boolean, default: false, desc: 'force generation migrations'
19
+
20
+ desc 'Runs rspec:paper_trail:install'
21
+
22
+ def generate_rspec_paper_trail_install
23
+ return if skip_migrations?
24
+ cli_opts = options.select { |key, val| val }.map { |key, val| val ? "--#{key}" : val.join(",") }
25
+ cmd = 'rspec:paper_trail:install ' + cli_opts.join(" ")
26
+ generate cmd
27
+ end
28
+
29
+ desc 'Generates updated rspec:paper_trail:install config'
30
+
31
+ def generate_updated_rspec_paper_trail_config
32
+ template 'features/versioning.rb', 'config/features/versioning.rb'
33
+ end
34
+
35
+ desc 'Runs smarter_dates:install'
36
+
37
+ def generate_smarter_dates_install
38
+ cli_opts = options.select { |key, val| val }.map { |key, val| val ? "--#{key}" : val.join(",") }
39
+ generate 'smarter_dates:install ' + cli_opts.join(" ")
40
+ end
41
+
42
+ desc 'Generates initialization files.'
43
+
44
+ def generate_configuration_files
45
+ template 'features/attachments.rb.erb', 'config/features/attachments.rb'
46
+ copy_file 'initializers/paperclip.rb', 'config/initializers/paperclip.rb'
47
+ end
48
+
49
+ desc 'Augments spec/spec_helper.rb for formtastic deployment'
50
+
51
+ def augment_spec_helper
52
+ insert_into_file 'config/environments/production.rb', ' config.assets.precompile += %w(ie6.css ie7.css)', after: "# config.assets.precompile += %w( search.js )\n"
53
+ end
54
+
55
+ private
56
+
57
+ def skip_migrations?
58
+ return true if options.send(:'skip-migrations')
59
+ false
60
+ end
61
+
62
+ def use_versioned_filename?
63
+ options.with_revision_in_filename?
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,7 @@
1
+ Configuration.for('attachments') do
2
+ enabled true
3
+ include_revision_in_filename <%= use_versioned_filename? %>
4
+ path ":rails_root/public/system/:rails_env/:style/:attachable_klass/:id_partition/:basename.:extension"
5
+ url ['development', 'test'].include?(Rails.env) ? "/attachments/:id/download" : "/system/:rails_env/:style/:attachable_klass/:id_partition/:basename.:extension"
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ Configuration.for('versioning') do
2
+ enabled true
3
+ validate_item_type_constants false
4
+ path ':rails_root/public/system/:rails_env/:style/:attachable_klass/:id_partition/:basename.:stream_version.:extension'
5
+ url %w(development test).include?(Rails.env) ? '/attachments/:id/download' : '/system/:rails_env/:style/:attachable_klass/:id_partition/:basename.:stream_version.:extension'
6
+ end
7
+
@@ -0,0 +1,27 @@
1
+ Paperclip.interpolates :stream_version do |attachment, _|
2
+ attachment.instance.revision_number
3
+ end
4
+
5
+ Paperclip.interpolates :attachable_klass do |attachment, _|
6
+ attachable_type = attachment.instance.attachable_type
7
+ attachable_type && attachable_type.respond_to?(:tableize) ? attachable_type.tableize : '.'
8
+ end
9
+
10
+ Paperclip.interpolates :rails_env do |_, _|
11
+ Rails.env
12
+ end
13
+
14
+ # brew on darwin
15
+ if File.directory?(File.join("", 'usr', 'local', 'bin'))
16
+ Paperclip.options[:command_path] = '/usr/local/bin'
17
+
18
+ # macports on darwin
19
+ elsif File.directory?(File.join("", 'opt', 'local', 'bin'))
20
+ Paperclip.options[:command_path] = '/opt/local/bin'
21
+
22
+ # "disabled" macports due to brew on darwin
23
+ elsif File.directory?(File.join("", 'opt', 'local.brew', 'bin'))
24
+ Paperclip.options[:command_path] = '/opt/local.brew/bin'
25
+ else
26
+ raise RuntimeError, 'can not locate identify binary'
27
+ end
@@ -0,0 +1,108 @@
1
+ module ImportableAttachments::Base
2
+ module ClassMethods
3
+
4
+ # :call-seq:
5
+ # has_importable_attachment opts
6
+ #
7
+ # = opts
8
+ # :import_method
9
+ # :import_into
10
+ # :spreadsheet_columns
11
+
12
+ def has_importable_attachment(options)
13
+ lopt = {import_method: :import_rows}
14
+ lopt.merge! options
15
+
16
+ validate_importable_attachment_options lopt
17
+ install_importable_attachment_options lopt
18
+ install_importable_attachment_associations
19
+ install_importable_attachment_validations
20
+ install_importable_attachment_assignment_protection
21
+
22
+ include InstanceMethods
23
+
24
+ # for assigning attachment to new record
25
+ after_create :import_attachment
26
+ end
27
+
28
+ def validate_importable_attachment_options(options)
29
+ [:spreadsheet_columns, :import_into].each do |sym|
30
+ raise RuntimeError, "has_importable_attachment: needs :#{sym}" unless options.has_key? sym
31
+ end
32
+
33
+ unless options[:spreadsheet_columns].is_a?(Enumerable)
34
+ raise RuntimeError, 'has_importable_attachment: :spreadsheet_columns must be Enumerable'
35
+ end
36
+ end
37
+
38
+ def install_importable_attachment_options(options)
39
+ [:import_method, :import_into, :spreadsheet_columns].each do |sym|
40
+ cattr_accessor sym
41
+ self.send("#{sym}=".to_sym, options[sym])
42
+ end
43
+ end
44
+
45
+ def install_importable_attachment_associations
46
+ has_one :attachment, :dependent => :nullify, :as => :attachable
47
+ delegate :io_stream, :to => :attachment, :prefix => true
48
+ delegate :io_stream_url, :to => :attachment, :prefix => true
49
+ delegate :io_stream_file_name, :to => :attachment, :prefix => true
50
+ end
51
+
52
+ def install_importable_attachment_validations
53
+ validates :attachment, :associated => true
54
+ validate do |record|
55
+ if @columns_not_found
56
+ invalid_attachment_error "column(s) not found: #{@columns_not_found}"
57
+ end
58
+ if !@row_errors.blank?
59
+ invalid_attachment_error "failed to import #{@row_errors.length} record(s)"
60
+ @row_errors.each {|row| attachment.errors.add(:base, row)}
61
+ end
62
+ end
63
+
64
+ # These go in the class calling has_importable_attachment as they are
65
+ # dependent on mime-type expectations
66
+ #validates_with CsvValidator, :if => Proc.new {|model| model.attachment.present?}
67
+ #validates_with ExcelValidator, :if => Proc.new {|model| model.attachment.present?}
68
+ end
69
+
70
+ def install_importable_attachment_assignment_protection
71
+ attr_accessible :attachment, :attachment_attributes, :attachment_id
72
+ accepts_nested_attributes_for :attachment, :allow_destroy => true,
73
+ :reject_if => :all_blank
74
+ end
75
+ end
76
+
77
+ module InstanceMethods
78
+ # : call-seq:
79
+ # import_attachment
80
+ #
81
+ # imports an attachment of a given mime-type (data-stream to ruby),
82
+ # calls import_rows with a ruby data-store
83
+ #
84
+ # NOTE: this is a stub
85
+
86
+ def import_attachment
87
+ raise RuntimeError, '[importable_attachments] .import_attachment not implemented'
88
+ end
89
+
90
+ # : call-seq:
91
+ # import_rows params
92
+ #
93
+ # imports an attachment contents into :import_into association
94
+ #
95
+ # NOTE: this is a stub
96
+
97
+ def import_rows(*opts)
98
+ return unless self.attachment
99
+ logger.debug "[importable_attachments] .import_rows #{opts}"
100
+ raise RuntimeError, '[importable_attachments] .import_rows not implemented'
101
+ end
102
+
103
+ def invalid_attachment_error(msg)
104
+ attachment.errors.add(:base, msg)
105
+ errors.add(:attachment, 'invalid attachment')
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,9 @@
1
+ require 'machinist/active_record'
2
+
3
+ ImportableAttachments::Attachment.blueprint do
4
+ io_stream { File.new Rails.root.join('spec', 'attachments', 'mostly_empty_copy.xls') }
5
+ end
6
+
7
+ Version.blueprint do
8
+ end
9
+
@@ -0,0 +1,8 @@
1
+ require 'configuration'
2
+ require 'rails/alpha_numeric_validator'
3
+
4
+ module ImportableAttachments
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace ImportableAttachments
7
+ end
8
+ end