fileclip 0.1.0 → 0.2.2

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
  SHA1:
3
- metadata.gz: 435bef9bd97c9e7a5a77ab0f26e68b2977d9cd48
4
- data.tar.gz: 2ffee75c354221079689f99cb4f86e13af632e5d
3
+ metadata.gz: f40a90259ac27e876f6cf56f326ab18279b476f5
4
+ data.tar.gz: decfde8e4d6ac8580cb2d86ec1c3394f37ca9333
5
5
  SHA512:
6
- metadata.gz: 36ecf1b9637d0e5bd6e1a8bb88e12aede0e7bfc310b1283d473d2c8029ee804742a1d154033c0f0f93626d206ac4ca8050c8601c5e88304e4eec4f2c2edd7f92
7
- data.tar.gz: cceec767215643332fe54b0f11fa0dbb538a8ffc21c5edf8a9f67d3d15ddc5a76d76d5b526444e052a3ac977306b6c69639bede4af1c0098ceb80fdeee3e09fb
6
+ metadata.gz: 9b1f34aef2c3516b4db6e14ae09ab4c6d1a08ade820374c71b9e64d33224b7336028f8104d4aa435095a367f6660619a174d92df3c65cc967cd3bf1d431aee96
7
+ data.tar.gz: 5b1c57b57955c4b3253dd8362d18b6c9b30ef0df73ef010cd3888ed9303ee59c5edb5d6996c108ef29d7fb4715bd4ef283f95caf843189788121b4b9c95d0b21
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1 @@
1
+ fileclip
@@ -0,0 +1 @@
1
+ 2.0.0-p247
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+
5
+ script:
6
+ - bundle exec rspec spec
7
+
8
+ notifications:
9
+ email:
10
+ - scott@artsicle.com
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fileclip (0.0.3)
4
+ fileclip (0.2.1)
5
5
  paperclip
6
- paperclip (>= 3.3.0)
6
+ paperclip (>= 3.5.1)
7
7
  railties (>= 3.0)
8
8
  rest-client
9
9
 
@@ -53,8 +53,9 @@ GEM
53
53
  mime-types (~> 1.16)
54
54
  treetop (~> 1.4.8)
55
55
  mime-types (1.23)
56
+ mono_logger (1.1.0)
56
57
  multi_json (1.7.7)
57
- paperclip (3.5.0)
58
+ paperclip (3.5.1)
58
59
  activemodel (>= 3.0.0)
59
60
  activesupport (>= 3.0.0)
60
61
  cocaine (~> 0.5.0)
@@ -63,6 +64,8 @@ GEM
63
64
  rack (1.4.5)
64
65
  rack-cache (1.2)
65
66
  rack (>= 0.4)
67
+ rack-protection (1.5.0)
68
+ rack
66
69
  rack-ssl (1.3.3)
67
70
  rack
68
71
  rack-test (0.6.2)
@@ -85,6 +88,15 @@ GEM
85
88
  rake (10.1.0)
86
89
  rdoc (3.12.2)
87
90
  json (~> 1.4)
91
+ redis (3.0.4)
92
+ redis-namespace (1.3.0)
93
+ redis (~> 3.0.0)
94
+ resque (1.24.1)
95
+ mono_logger (~> 1.0)
96
+ multi_json (~> 1.0)
97
+ redis-namespace (~> 1.2)
98
+ sinatra (>= 0.9.2)
99
+ vegas (~> 0.1.2)
88
100
  rest-client (1.6.7)
89
101
  mime-types (>= 1.16)
90
102
  rspec (2.14.1)
@@ -95,6 +107,10 @@ GEM
95
107
  rspec-expectations (2.14.0)
96
108
  diff-lcs (>= 1.1.3, < 2.0)
97
109
  rspec-mocks (2.14.1)
110
+ sinatra (1.4.3)
111
+ rack (~> 1.4)
112
+ rack-protection (~> 1.4)
113
+ tilt (~> 1.3, >= 1.3.4)
98
114
  sprockets (2.2.2)
99
115
  hike (~> 1.2)
100
116
  multi_json (~> 1.0)
@@ -107,6 +123,8 @@ GEM
107
123
  polyglot
108
124
  polyglot (>= 0.3.1)
109
125
  tzinfo (0.3.37)
126
+ vegas (0.1.11)
127
+ rack (>= 1.0.0)
110
128
 
111
129
  PLATFORMS
112
130
  ruby
@@ -114,5 +132,6 @@ PLATFORMS
114
132
  DEPENDENCIES
115
133
  fileclip!
116
134
  rails (= 3.2.14)
135
+ resque
117
136
  rspec
118
137
  sqlite3
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- FileClip
1
+ FileClip [![Build Status](https://travis-ci.org/ScotterC/fileclip.png?branch=master)](https://travis-ci.org/ScotterC/fileclip)
2
2
  ========
3
3
 
4
4
  A FilePicker / PaperClip mashup. Use Filepicker for uploads and paperclip to process them.
@@ -28,6 +28,22 @@ end
28
28
  # config/initializers/fileclip.rb
29
29
  FileClip.configure do |config|
30
30
  config.filepicker_key = 'XXXXXXXXXXXXXXXXXXX'
31
+ config.services = ["COMPUTER", "DROPBOX"] # Defaults to ["COMPUTER"]
32
+ config.max_size = 20 # Megabytes, defaults to 20
33
+ config.storage_path = "/assets/" # Defaults to "/fileclip/"
34
+ config.mime_types = "images/jpeg" # Defaults to "images/*"
35
+ config.file_access = "private" # Defaults to "public"
36
+ end
37
+ ````
38
+
39
+ ### In Model
40
+ ````
41
+ # models/image.rb
42
+ class Image << ActiveRecord::Base
43
+
44
+ has_attached_file :attachment
45
+
46
+ fileclip :attachment
31
47
  end
32
48
  ````
33
49
 
@@ -48,10 +64,21 @@ end
48
64
  ````
49
65
 
50
66
  #### Current FilePicker options hardcoded
51
- * mimetypes are image/*
52
67
  * container modal
53
- * service Computer
54
- * maxsize is 20 mb
55
68
  * location is S3
56
- * path is "/fileclip"
57
- * access is public
69
+
70
+ Features:
71
+ * Unobtrusive. Normal paperclip uploads still work
72
+
73
+
74
+ #### Gotchas
75
+
76
+ This paperclip validation will return errors even if filepicker url is present:
77
+ ````
78
+ validates :attachment, :attachment_presence => true
79
+ ````
80
+
81
+ However, this will work fine. It'll skip the attachment check if a filepicker url is present and validate if it's not.
82
+ ````
83
+ validates_attachment :attachment, :size => { :in => 0..1000 }, :presence => true
84
+ ````
data/TODO.md ADDED
@@ -0,0 +1,28 @@
1
+ TODO:
2
+
3
+ Backend:
4
+ * handle multiple attachments on a model, prefix column with attachment name
5
+ * create generator for migration
6
+ * create generator for intializer
7
+ * Normalize filenames
8
+ * Change keys as an option. defaults to filepicker_url
9
+
10
+ Frontend:
11
+ * Allow overriding of filepicker options
12
+ * Fileclip link to automatically set fields and call it
13
+ * link should act like a normal link helper
14
+ * Minimal amount of JS
15
+ * Loader for filepicker js only if needed
16
+ * Eliminate need for jQuery
17
+ * make it a form builder function that can accept a different url name
18
+
19
+ Extra features:
20
+ * Work with Delayed Paperclip
21
+ * Work with Resque
22
+ * Work with DelayedJob
23
+ * Work with Sidekiq
24
+ * Fallback to filepicker url if paperclip url doesn't exist
25
+ * Filepicker converts to match paperclip styles
26
+ * Configure Filepicker options
27
+ * FilePicker droppane support
28
+
@@ -2,41 +2,28 @@ $:.push File.expand_path("../lib", __FILE__)
2
2
  require "fileclip/version"
3
3
 
4
4
  Gem::Specification.new do |s|
5
- s.name = "fileclip"
6
- s.version = FileClip::VERSION
5
+ s.name = "fileclip"
6
+ s.version = FileClip::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Scott Carleton"]
9
+ s.summary = "A FilePicker / PaperClip mashup."
10
+ s.description = "A FilePicker / PaperClip mashup. Use Filepicker for uploads and paperclip to process them."
11
+ s.email = "scott@artsicle.com"
12
+ s.license = "MIT"
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.homepage = "http://github.com/ScotterC/fileclip"
7
17
 
8
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
- s.authors = ["Scott Carleton"]
10
- s.date = "2013-07-26"
11
- s.description = "A FilePicker / PaperClip mashup. Use Filepicker for uploads and paperclip to process them."
12
- s.email = "scott@artsicle.com"
13
- s.extra_rdoc_files = [
14
- "LICENSE",
15
- "README.md"
16
- ]
17
- s.files = [
18
- ".document",
19
- "Gemfile",
20
- "Gemfile.lock",
21
- "LICENSE",
22
- "README.md",
23
- "Rakefile",
24
- "fileclip.gemspec",
25
- "lib/fileclip.rb",
26
- "lib/fileclip/version.rb"
27
- ]
28
- s.homepage = "http://github.com/ScotterC/fileclip"
29
- s.licenses = ["MIT"]
30
- s.require_paths = ["lib"]
31
18
  s.rubygems_version = "2.0.3"
32
- s.summary = "A FilePicker / PaperClip mashup."
33
19
 
34
- s.add_dependency 'paperclip', [">= 3.3.0"]
20
+ s.add_dependency 'paperclip', [">= 3.5.1"]
35
21
  s.add_dependency 'rest-client'
36
22
 
37
23
  s.add_development_dependency "rspec"
38
24
  s.add_development_dependency 'sqlite3'
39
25
  s.add_development_dependency "rails"
26
+ s.add_development_dependency 'resque'
40
27
  s.add_runtime_dependency(%q<railties>, [">= 3.0"])
41
28
 
42
29
  s.add_runtime_dependency "paperclip"
@@ -1,75 +1,66 @@
1
- # TODO
2
- #
3
- # Allowance for normal attached images through file_field:
4
- # only do attachment validation if it's there if remote url is not present
5
- # only do process_in_background if remote_url is not present
6
- #
7
- # Expose FilePicked to all classes that have Paperclip images
8
- #
9
- # Handle multiple attachments in single model
10
- # Crux of this is finding the name of the attachment we're dealing with
11
- #
12
- # Fallback if none are defined
13
- #
14
- # What can we separate out into it's own class
15
- # What should be a part of attachment
16
- #
17
- # Migration generator
18
- #
19
- # Configuration to take Filepicker API key
20
- #
21
- # Javascript inclusion
22
- #
23
- # Add delayed aspect
24
- #
25
- # Queue job for image assignment
26
1
  require 'fileclip/configuration'
27
2
  require 'fileclip/action_view/helpers'
3
+ require 'fileclip/validators'
28
4
  require 'fileclip/engine'
29
5
  require 'fileclip/railtie'
6
+ require 'fileclip/jobs/resque'
30
7
  require 'rest-client'
31
8
 
32
9
  module FileClip
33
10
 
11
+ mattr_accessor :change_keys
12
+
13
+ def self.change_keys
14
+ @@change_keys ||= [:filepicker_url]
15
+ end
16
+
17
+ def self.delayed?
18
+ defined?(DelayedPaperclip)
19
+ # TODO: replace with checking for delayed options?
20
+ end
21
+
22
+ class << self
23
+
24
+ def resque_enabled?
25
+ !!(defined? Resque)
26
+ end
27
+
28
+ def process(klass, instance_id)
29
+ klass.constantize.find(instance_id).process_from_filepicker
30
+ end
31
+
32
+ end
33
+
34
34
  module Glue
35
35
  def self.included(base)
36
- base.extend(ClassMethods)
36
+ base.extend ClassMethods
37
+ base.extend FileClip::Validators::HelperMethods
37
38
  base.send :include, InstanceMethods
38
- base.add_callbacks
39
39
  end
40
40
  end
41
41
 
42
42
  module ClassMethods
43
- def add_callbacks
43
+ def fileclip(name)
44
44
  attr_accessible :filepicker_url
45
+ after_commit :update_from_filepicker!
45
46
 
46
- # if respond_to?(:after_commit)
47
- after_commit :update_from_filepicker!
48
- # else
49
- # after_save :update_from_filepicker!
50
- # end
47
+ set_fileclipped(name)
48
+ end
51
49
 
52
- # TODO:
53
- # skip validates_attachment_presence if filepicker url present
54
- # Save without this particular vaildation
50
+ def fileclipped
51
+ @attachment_name
55
52
  end
56
53
 
57
- def paperclip_definitions
58
- @paperclip_definitions ||= if Paperclip::VERSION.to_f < 3.5
59
- attachment_definitions
60
- elsif Paperclip::VERSION == "3.5.0"
61
- Paperclip::Tasks::Attachments.definitions_for(self)
62
- else
63
- Paperclip::AttachmentRegistry.definitions_for(self)
64
- end
54
+ def set_fileclipped(name)
55
+ @attachment_name = name
65
56
  end
66
57
  end
67
58
 
68
59
  module InstanceMethods
69
60
 
70
- # TODO: can't handle multiples, just first
61
+ # TODO: can't handle multiples, just given
71
62
  def attachment_name
72
- @attachment_name ||= self.class.paperclip_definitions.keys.first
63
+ @attachment_name ||= self.class.fileclipped
73
64
  end
74
65
 
75
66
  def attachment_object
@@ -77,14 +68,28 @@ module FileClip
77
68
  end
78
69
 
79
70
  def update_from_filepicker!
80
- process_from_filepicker if update_from_filepicker?
71
+ if update_from_filepicker?
72
+ if FileClip.resque_enabled?
73
+ # TODO: self.class.name is webrick ???
74
+ delay_process!
75
+ else
76
+ process_from_filepicker
77
+ end
78
+ end
79
+ end
80
+
81
+ def delay_process!
82
+ update_column(:"#{attachment_name}_processing", true) if FileClip.delayed?
83
+ Resque.enqueue(FileClip::Jobs::Resque, self.class.name, self.id)
81
84
  end
82
85
 
83
86
  def process_from_filepicker
84
87
  self.class.skip_callback :commit, :after, :update_from_filepicker!
85
88
  self.send(:"#{attachment_name}=", URI.parse(filepicker_url))
86
89
  self.set_metadata
90
+ self.attachment_object.save_with_prepare_enqueueing if FileClip.delayed?
87
91
  self.save
92
+ self.enqueue_delayed_processing if FileClip.delayed?
88
93
  self.class.set_callback :commit, :after, :update_from_filepicker!
89
94
  end
90
95
 
@@ -97,7 +102,7 @@ module FileClip
97
102
  end
98
103
 
99
104
  def update_from_filepicker?
100
- filepicker_url_previously_changed? &&
105
+ fileclip_previously_changed? &&
101
106
  filepicker_url.present? &&
102
107
  !filepicker_only?
103
108
  end
@@ -106,8 +111,8 @@ module FileClip
106
111
  !filepicker_url.present?
107
112
  end
108
113
 
109
- def filepicker_url_previously_changed?
110
- previous_changes.keys.include?('filepicker_url')
114
+ def fileclip_previously_changed?
115
+ !(previous_changes.keys.map(&:to_sym) & FileClip.change_keys).empty?
111
116
  end
112
117
 
113
118
  # To be overridden in model if specific logic for not
@@ -0,0 +1,69 @@
1
+ module FileClip
2
+ module ActionView
3
+ module Helpers
4
+
5
+ # Include relevant JS
6
+ def fileclip_js_include_tag
7
+ javascript_include_tag "//api.filepicker.io/v1/filepicker.js", "fileclip"
8
+ end
9
+
10
+ # Options
11
+ # js to activate it on the spot, defaults to true
12
+ # class to add css classes
13
+ def link_to_fileclip(text, form_object, options={}, &block)
14
+ form_object, options = text, form_object if block_given?
15
+
16
+ id = fileclip_id(form_object)
17
+ classes = fileclip_css_classes(options[:class])
18
+
19
+ # Got to be a cleaner way to do this
20
+ link = if block_given?
21
+ link_to "javascript:void(0)", class: classes, id: id, &block
22
+ else
23
+ link_to text, "javascript:void(0)", class: classes, id: id
24
+ end
25
+
26
+ fileclip_link_builder(link, form_object, options, id)
27
+ end
28
+
29
+ # Add js-fileclip to existing classes
30
+ def fileclip_css_classes(given_classes)
31
+ return "js-fileclip" if given_classes.nil?
32
+ css_classes = [].push(given_classes.split)
33
+ css_classes << "js-fileclip"
34
+ css_classes
35
+ end
36
+
37
+ # Object id for link
38
+ def fileclip_id(form_object)
39
+ new_object = form_object.object
40
+ attachment_name = new_object.attachment_name
41
+ "#{attachment_name}_#{new_object.object_id}"
42
+ end
43
+
44
+ # Return empty tag if it's nil or true
45
+ def activation(js, id)
46
+ return javascript_tag unless js.nil? || js
47
+
48
+ javascript_tag("(function() {
49
+ (new FileClip).button('##{id}');
50
+ })();")
51
+ end
52
+
53
+ # Options
54
+ # Activate (defaults to true) to set own javascript
55
+ def fileclip_link_builder(link, form_object, options, id)
56
+ # Get attachment name
57
+ attachment_name = form_object.object.attachment_name
58
+
59
+ js = activation(options[:js], id)
60
+
61
+ js + link +
62
+ form_object.hidden_field(:filepicker_url,
63
+ class: "js-fileclip_url",
64
+ data: { type: attachment_name })
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,42 @@
1
+ module FileClip
2
+ class Configuration
3
+ attr_writer :filepicker_key, :services,
4
+ :max_size, :storage_path,
5
+ :mime_types, :file_access
6
+
7
+ def filepicker_key
8
+ @filepicker_key or raise "Set Filepicker api_key"
9
+ end
10
+
11
+ def services
12
+ @services or ["COMPUTER"]
13
+ end
14
+
15
+ def max_size
16
+ @max_size or 20
17
+ end
18
+
19
+ def storage_path
20
+ @storage_path or "/fileclip/"
21
+ end
22
+
23
+ def mime_types
24
+ @mime_types or "image/*"
25
+ end
26
+
27
+ def file_access
28
+ @file_access or "public"
29
+ end
30
+
31
+ end
32
+
33
+ class << self
34
+ def configure
35
+ yield configuration
36
+ end
37
+
38
+ def configuration
39
+ @configuration ||= FileClip::Configuration.new
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,11 @@
1
+ module FileClip
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ initializer 'fileclip.insert_into_active_record' do
5
+ ::ActiveSupport.on_load :active_record do
6
+ FileClip::Railtie.insert
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module FileClip
2
+ module Jobs
3
+ class Resque
4
+ @queue = :fileclip
5
+
6
+ def self.perform(instance_klass, instance_id)
7
+ FileClip.process(instance_klass, instance_id)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module FileClip
2
+ class Railtie
3
+ # Glue includes FileClip into ActiveRecord
4
+ # TODO: only include it in models that have paperclip attachments
5
+ # Will require restart of server for it to pick up the class on edit
6
+ def self.insert
7
+ ::ActiveRecord::Base.send(:include, FileClip::Glue)
8
+ ::ActionView::Base.send(:include, FileClip::ActionView::Helpers)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module FileClip
2
+ module Validators
3
+
4
+ module HelperMethods
5
+
6
+ def validates_attachment_content_type(*attr_names)
7
+ attr_names.last.merge!({ :if => :filepicker_url_not_present? })
8
+ super(*attr_names)
9
+ end
10
+
11
+ def validates_attachment_presence(*attr_names)
12
+ attr_names.last.merge!({ :if => :filepicker_url_not_present? })
13
+ super(*attr_names)
14
+ end
15
+
16
+ def validates_attachment_size(*attr_names)
17
+ attr_names.last.merge!({ :if => :filepicker_url_not_present? })
18
+ super(*attr_names)
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  module FileClip
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe FileClip::Configuration do
4
+
5
+ describe "filepicker_key" do
6
+ it "should be nil to start" do
7
+ expect { FileClip.configuration.filepicker_key }.to raise_error
8
+ end
9
+
10
+ it "should be set by block" do
11
+ FileClip.configure do |config|
12
+ config.filepicker_key = "XXX-XXX"
13
+ end
14
+ FileClip.configuration.filepicker_key.should == "XXX-XXX"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'rails/initializable'
3
+
4
+
5
+ describe FileClip::Rails::Engine do
6
+
7
+ describe "include on initialzation" do
8
+ it "should insert fileclip and include view helpers on rails initialzation" do
9
+ pending
10
+ FileClip::Railtie.should_receive(:insert)
11
+ ::ActionView::Base.should_receive(:send).with(:include, FileClip::ActionView::Helpers)
12
+ FileClip::Rails::Engine.run_initializers
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe FileClip::Railtie do
4
+ describe "insert" do
5
+ it "should include the glue" do
6
+ ActiveRecord::Base.should_receive(:send).with(:include, FileClip::Glue)
7
+ ActionView::Base.should_receive(:send).with(:include, FileClip::ActionView::Helpers)
8
+ FileClip::Railtie.insert
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe FileClip::Validators do
4
+ let(:image) { Image.new }
5
+
6
+ describe "validations" do
7
+ before :each do
8
+ Image.reset_callbacks(:validate)
9
+ Image._validators.clear
10
+ end
11
+
12
+ describe "if no filepicker_url" do
13
+ it "observes attachment presence" do
14
+ Image.validates :attachment, :attachment_presence => true
15
+ image.save.should be_false
16
+ image.errors.first.last.should == "can't be blank"
17
+ end
18
+
19
+ it "observes attachment size" do
20
+ Image.validates_attachment :attachment, :size => { :in => 0..1000 }, :presence => true
21
+ image.save.should be_false
22
+ image.errors.should_not be_empty
23
+ end
24
+
25
+ it "observes attachment content" do
26
+ Image.validates_attachment :attachment, :content_type => { :content_type => "image/jpg" }, :presence => true
27
+ image.save.should be_false
28
+ image.errors.should_not be_empty
29
+ end
30
+ end
31
+
32
+ describe "with filepicker url" do
33
+ before :each do
34
+ image.filepicker_url = "image.com"
35
+ end
36
+
37
+ it "observes attachment presence" do
38
+ pending
39
+ Image.validates :attachment, :attachment_presence => true
40
+ image.save.should be_true
41
+ image.errors.should be_empty
42
+ end
43
+
44
+ it "observes attachment size" do
45
+ Image.validates_attachment :attachment, :size => { :in => 0..1000 }, :presence => true
46
+ image.save.should be_true
47
+ image.errors.should be_empty
48
+ end
49
+
50
+ it "observes attachment content" do
51
+ Image.validates_attachment :attachment, :content_type => { :content_type => "image/jpg" }, :presence => true
52
+ image.save.should be_true
53
+ image.errors.should be_empty
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,214 @@
1
+ require 'spec_helper'
2
+
3
+ describe FileClip do
4
+ let(:filepicker_url) { "https://www.filepicker.io/api/file/ibOold9OQfqbmzgP6D3O" }
5
+ let(:image) { Image.new }
6
+ let(:uri) { URI.parse(filepicker_url) }
7
+
8
+ describe "change keys" do
9
+ it "defaults to just fileclip_url" do
10
+ FileClip.change_keys.should == [:filepicker_url]
11
+ end
12
+
13
+ it "can be added to" do
14
+ FileClip.change_keys << :file_name
15
+ FileClip.change_keys.should == [:filepicker_url, :file_name]
16
+ end
17
+ end
18
+
19
+ describe ".delayed?" do
20
+ it "returns false without delayed paperclip" do
21
+ FileClip.delayed?.should be_false
22
+ end
23
+
24
+ it "returns true if delayed paperclip exists" do
25
+ stub_const("DelayedPaperclip", true)
26
+ FileClip.delayed?.should be_true
27
+ end
28
+ end
29
+
30
+ describe "class_methods" do
31
+ describe "fileclip" do
32
+ it "should register callback when called" do
33
+ Image.fileclip :attachment
34
+ Image._commit_callbacks.first.filter.should == :update_from_filepicker!
35
+ end
36
+
37
+ it "registers after save callback if commit is not available" do
38
+ pending # Skipping either callback
39
+ Image._save_callbacks.first.filter.should_not == :update_from_filepicker!
40
+ Image.stub(:respond_to?).with(:after_commit).and_return false
41
+ FileClip::Glue.included(Image)
42
+ Image._save_callbacks.first.filter.should == :update_from_filepicker!
43
+ end
44
+
45
+ it "adds name to fileclipped" do
46
+ Image.fileclipped.should == :attachment
47
+ Image.fileclip(:image)
48
+ Image.fileclipped.should == :image
49
+ Image.fileclip(:attachment) # set it back for other tests
50
+ end
51
+ end
52
+
53
+ describe "resque_enabled?" do
54
+ it "returns false by default" do
55
+ FileClip.resque_enabled?.should be_false
56
+ end
57
+
58
+ it "returns true if resque exists" do
59
+ stub_const "Resque", Class.new
60
+ FileClip.resque_enabled?.should be_true
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "instance methods" do
66
+ context "#attachment_name" do
67
+ context "image" do
68
+ it "should return :attachment" do
69
+ image.attachment_name.should == :attachment
70
+ end
71
+ end
72
+ end
73
+
74
+ context "#attachment_object" do
75
+ context "image" do
76
+ it "should receive attachment" do
77
+ image.should_receive(:attachment)
78
+ image.attachment_object
79
+ end
80
+ end
81
+ end
82
+
83
+ context "#update_from_filepicker!" do
84
+
85
+ context "without resque" do
86
+ before :each do
87
+ image.filepicker_url = filepicker_url
88
+ image.stub_chain(:previous_changes, :keys).and_return ["filepicker_url"]
89
+ end
90
+
91
+ context "image" do
92
+ it "should process image" do
93
+ image.should_receive(:process_from_filepicker)
94
+ image.update_from_filepicker!
95
+ end
96
+ end
97
+ end
98
+
99
+ context "with resque" do
100
+ before :each do
101
+ image.filepicker_url = filepicker_url
102
+ image.stub_chain(:previous_changes, :keys).and_return ["filepicker_url"]
103
+ end
104
+
105
+ it "enqueues job" do
106
+ stub_const "Resque", Class.new
107
+ Resque.should_receive(:enqueue).with(FileClip::Jobs::Resque, "Image", nil)
108
+ image.update_from_filepicker!
109
+ end
110
+ end
111
+ end
112
+
113
+ context "#update_from_filepicker?" do
114
+ it "should be false with only a filepicker url" do
115
+ image.filepicker_url = filepicker_url
116
+ image.update_from_filepicker?.should be_false
117
+ end
118
+
119
+ it "should be false without a filepicker" do
120
+ image.stub_chain(:previous_changes, :keys).and_return ["filepicker_url"]
121
+ image.update_from_filepicker?.should be_false
122
+ end
123
+
124
+ it "should be true if filepicker url exists and is changed" do
125
+ image.filepicker_url = filepicker_url
126
+ image.stub_chain(:previous_changes, :keys).and_return ["filepicker_url"]
127
+ image.update_from_filepicker?.should be_true
128
+ end
129
+ end
130
+
131
+ context "#process_from_filepicker" do
132
+ context "not delayed" do
133
+ context "image" do
134
+ before :each do
135
+ image.filepicker_url = filepicker_url
136
+ end
137
+
138
+ it "should set attachment and save" do
139
+ image.should_receive(:attachment=).with(uri)
140
+ image.should_receive(:save)
141
+ image.process_from_filepicker
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ context "#filepicker_url_not_present?" do
148
+ it "should return true" do
149
+ image.filepicker_url_not_present?.should == true
150
+ end
151
+
152
+ context "with filepicker url" do
153
+ before :each do
154
+ image.filepicker_url = filepicker_url
155
+ end
156
+
157
+ it "should return false" do
158
+ image.filepicker_url_not_present?.should == false
159
+ end
160
+ end
161
+ end
162
+
163
+ context "#fileclip_previously_changed?" do
164
+ it "should return true with previous changed filepicker_url" do
165
+ image.stub_chain(:previous_changes, :keys).and_return ["filepicker_url"]
166
+ image.fileclip_previously_changed?.should be_true
167
+ end
168
+
169
+ it "should return false without previously changed filepicker_url" do
170
+ image.stub_chain(:previous_changes, :keys).and_return []
171
+ image.fileclip_previously_changed?.should be_false
172
+ end
173
+ end
174
+
175
+ def raw_data
176
+ "{\"mimetype\": \"image/gif\", \"uploaded\": 1374701729162.0, \"writeable\": true, \"filename\": \"140x100.gif\", \"location\": \"S3\", \"path\": \"tmp/tMrYkwI0RWOv0R13hALu_140x100.gif\", \"size\": 449}"
177
+ end
178
+
179
+ def metadata
180
+ {"mimetype" => "image/gif",
181
+ "uploaded" => 1374701729162.0,
182
+ "writeable" => true,
183
+ "filename" => "140x100.gif",
184
+ "location" => "S3",
185
+ "path" => "tmp/tMrYkwI0RWOv0R13hALu_140x100.gif",
186
+ "size" => 449 }
187
+ end
188
+
189
+
190
+ context "assign metadata" do
191
+ before :each do
192
+ image.filepicker_url = filepicker_url
193
+ RestClient.stub(:get).with(image.filepicker_url + "/metadata").and_return raw_data
194
+ end
195
+
196
+ it "sets metadata from filepicker" do
197
+ image.set_metadata
198
+ image.attachment_content_type.should == "image/gif"
199
+ image.attachment_file_name.should == "140x100.gif"
200
+ image.attachment_file_size.should == 449
201
+ end
202
+
203
+ context "process_from_filepicker" do
204
+ it "sets data and uploads attachment" do
205
+ image.process_from_filepicker
206
+ image.attachment_content_type.should == "image/gif"
207
+ image.attachment_file_name.should == "140x100.gif"
208
+ image.attachment_file_size.should == 449
209
+ end
210
+ end
211
+ end
212
+
213
+ end
214
+ end
@@ -0,0 +1,10 @@
1
+ ActiveRecord::Schema.define :version => 0 do
2
+ create_table "images", :force => true do |t|
3
+ t.string :attachment_file_name
4
+ t.string :attachment_content_type
5
+ t.integer :attachment_updated_at
6
+ t.integer :attachment_file_size
7
+ t.string :attachment_meta
8
+ t.string :filepicker_url
9
+ end
10
+ end
@@ -0,0 +1,34 @@
1
+ require 'rubygems' unless defined? Gem
2
+ require 'bundler'
3
+ Bundler.setup
4
+
5
+ # Prepare activerecord
6
+ # require "active_record"
7
+ require 'rails/all'
8
+
9
+ # Connect to sqlite
10
+ ActiveRecord::Base.establish_connection(
11
+ "adapter" => "sqlite3",
12
+ "database" => ":memory:"
13
+ )
14
+
15
+ ActiveRecord::Migration.verbose = false
16
+ load(File.join(File.dirname(__FILE__), 'schema.rb'))
17
+
18
+ require 'paperclip'
19
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
20
+
21
+ require 'fileclip'
22
+ ActiveRecord::Base.send(:include, FileClip::Glue)
23
+
24
+
25
+ class Image < ActiveRecord::Base
26
+
27
+ has_attached_file :attachment,
28
+ :storage => :filesystem,
29
+ :path => "./spec/tmp/:style/:id.:extension",
30
+ :url => "./spec/tmp/:style/:id.extension"
31
+
32
+ fileclip :attachment
33
+
34
+ end
@@ -0,0 +1,57 @@
1
+ class window.FileClip
2
+ _clicked_button: ""
3
+
4
+ constructor: ->
5
+ filepicker.setKey('<%= FileClip.configuration.filepicker_key %>');
6
+
7
+ # For filepicker_helper
8
+ # Accepts button that to be clicked and optional callback
9
+ button: (target, callback) ->
10
+ $(document).on "click", target, =>
11
+ @buttonHandler(target, callback)
12
+
13
+ # Handler to set which button was clicked and to pass on callback
14
+ # To puicker
15
+ buttonHandler: (target, callback) ->
16
+ @_clicked_button = $(target)
17
+ @picker(callback)
18
+
19
+ picker: (callback) =>
20
+ filepicker.pickAndStore
21
+ mimetypes: "<%= FileClip.configuration.mime_types %>"
22
+ container: "modal"
23
+ services: <%= FileClip.configuration.services %>
24
+ maxSize: (<%= FileClip.configuration.max_size %> * 1024 * 1024)
25
+ ,
26
+ location: "S3"
27
+ path: "<%= FileClip.configuration.storage_path %>"
28
+ access: "<%= FileClip.configuration.file_access %>"
29
+ , (fpfile) =>
30
+ @imageHandler fpfile, callback
31
+ , (error) =>
32
+ console.log error.code
33
+
34
+ # Accepts a filepicker file and optional callback
35
+ # Passes file and button clicked to a callback
36
+ # Target if passed in
37
+ # id to look up the link where it should be going
38
+ # or clicked button's next input
39
+ imageHandler: (fpfile, callback, target) ->
40
+ file = fpfile[0]
41
+
42
+ $file_target = if not @_clicked_button
43
+ $(target).find(".js-fileclip_url")
44
+ else if @_clicked_button.data("id")
45
+ $("##{@_clicked_button.data("id")}").next(".js-fileclip_url")
46
+ else
47
+ @_clicked_button.next(".js-fileclip_url")
48
+
49
+ if $file_target.length > 0
50
+ $file_target.val file.url
51
+ else
52
+ console.log "File Failed to Save"
53
+
54
+ callback(file, @_clicked_button) if callback
55
+
56
+
57
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fileclip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Carleton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-26 00:00:00.000000000 Z
11
+ date: 2013-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: paperclip
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '>='
18
18
  - !ruby/object:Gem::Version
19
- version: 3.3.0
19
+ version: 3.5.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
- version: 3.3.0
26
+ version: 3.5.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rest-client
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: resque
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: railties
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -113,19 +127,37 @@ description: A FilePicker / PaperClip mashup. Use Filepicker for uploads and pa
113
127
  email: scott@artsicle.com
114
128
  executables: []
115
129
  extensions: []
116
- extra_rdoc_files:
117
- - LICENSE
118
- - README.md
130
+ extra_rdoc_files: []
119
131
  files:
120
132
  - .document
133
+ - .gitignore
134
+ - .rspec
135
+ - .ruby-gemset
136
+ - .ruby-version
137
+ - .travis.yml
121
138
  - Gemfile
122
139
  - Gemfile.lock
123
140
  - LICENSE
124
141
  - README.md
125
142
  - Rakefile
143
+ - TODO.md
126
144
  - fileclip.gemspec
127
145
  - lib/fileclip.rb
146
+ - lib/fileclip/action_view/helpers.rb
147
+ - lib/fileclip/configuration.rb
148
+ - lib/fileclip/engine.rb
149
+ - lib/fileclip/jobs/resque.rb
150
+ - lib/fileclip/railtie.rb
151
+ - lib/fileclip/validators.rb
128
152
  - lib/fileclip/version.rb
153
+ - spec/fileclip/configuration_spec.rb
154
+ - spec/fileclip/engine_spec.rb
155
+ - spec/fileclip/railtie_spec.rb
156
+ - spec/fileclip/validators_spec.rb
157
+ - spec/fileclip_spec.rb
158
+ - spec/schema.rb
159
+ - spec/spec_helper.rb
160
+ - vendor/assets/javascripts/fileclip.js.coffee.erb
129
161
  homepage: http://github.com/ScotterC/fileclip
130
162
  licenses:
131
163
  - MIT
@@ -150,4 +182,11 @@ rubygems_version: 2.0.6
150
182
  signing_key:
151
183
  specification_version: 4
152
184
  summary: A FilePicker / PaperClip mashup.
153
- test_files: []
185
+ test_files:
186
+ - spec/fileclip/configuration_spec.rb
187
+ - spec/fileclip/engine_spec.rb
188
+ - spec/fileclip/railtie_spec.rb
189
+ - spec/fileclip/validators_spec.rb
190
+ - spec/fileclip_spec.rb
191
+ - spec/schema.rb
192
+ - spec/spec_helper.rb