the_storages 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/images/content_types/default.jpg +0 -0
- data/app/assets/images/content_types/file_extension_3gp.png +0 -0
- data/app/assets/images/content_types/file_extension_7z.png +0 -0
- data/app/assets/images/content_types/file_extension_ace.png +0 -0
- data/app/assets/images/content_types/file_extension_ai.png +0 -0
- data/app/assets/images/content_types/file_extension_aif.png +0 -0
- data/app/assets/images/content_types/file_extension_aiff.png +0 -0
- data/app/assets/images/content_types/file_extension_amr.png +0 -0
- data/app/assets/images/content_types/file_extension_asf.png +0 -0
- data/app/assets/images/content_types/file_extension_asx.png +0 -0
- data/app/assets/images/content_types/file_extension_bat.png +0 -0
- data/app/assets/images/content_types/file_extension_bin.png +0 -0
- data/app/assets/images/content_types/file_extension_bmp.png +0 -0
- data/app/assets/images/content_types/file_extension_bup.png +0 -0
- data/app/assets/images/content_types/file_extension_cab.png +0 -0
- data/app/assets/images/content_types/file_extension_cbr.png +0 -0
- data/app/assets/images/content_types/file_extension_cda.png +0 -0
- data/app/assets/images/content_types/file_extension_cdl.png +0 -0
- data/app/assets/images/content_types/file_extension_cdr.png +0 -0
- data/app/assets/images/content_types/file_extension_chm.png +0 -0
- data/app/assets/images/content_types/file_extension_dat.png +0 -0
- data/app/assets/images/content_types/file_extension_divx.png +0 -0
- data/app/assets/images/content_types/file_extension_dll.png +0 -0
- data/app/assets/images/content_types/file_extension_dmg.png +0 -0
- data/app/assets/images/content_types/file_extension_doc.png +0 -0
- data/app/assets/images/content_types/file_extension_docx.png +0 -0
- data/app/assets/images/content_types/file_extension_dss.png +0 -0
- data/app/assets/images/content_types/file_extension_dvf.png +0 -0
- data/app/assets/images/content_types/file_extension_dwg.png +0 -0
- data/app/assets/images/content_types/file_extension_eml.png +0 -0
- data/app/assets/images/content_types/file_extension_eps.png +0 -0
- data/app/assets/images/content_types/file_extension_exe.png +0 -0
- data/app/assets/images/content_types/file_extension_fla.png +0 -0
- data/app/assets/images/content_types/file_extension_flv.png +0 -0
- data/app/assets/images/content_types/file_extension_gif.png +0 -0
- data/app/assets/images/content_types/file_extension_gz.png +0 -0
- data/app/assets/images/content_types/file_extension_hqx.png +0 -0
- data/app/assets/images/content_types/file_extension_htm.png +0 -0
- data/app/assets/images/content_types/file_extension_html.png +0 -0
- data/app/assets/images/content_types/file_extension_ifo.png +0 -0
- data/app/assets/images/content_types/file_extension_indd.png +0 -0
- data/app/assets/images/content_types/file_extension_iso.png +0 -0
- data/app/assets/images/content_types/file_extension_jar.png +0 -0
- data/app/assets/images/content_types/file_extension_jpeg.png +0 -0
- data/app/assets/images/content_types/file_extension_jpg.png +0 -0
- data/app/assets/images/content_types/file_extension_lnk.png +0 -0
- data/app/assets/images/content_types/file_extension_log.png +0 -0
- data/app/assets/images/content_types/file_extension_m4a.png +0 -0
- data/app/assets/images/content_types/file_extension_m4b.png +0 -0
- data/app/assets/images/content_types/file_extension_m4p.png +0 -0
- data/app/assets/images/content_types/file_extension_m4v.png +0 -0
- data/app/assets/images/content_types/file_extension_mcd.png +0 -0
- data/app/assets/images/content_types/file_extension_mdb.png +0 -0
- data/app/assets/images/content_types/file_extension_mid.png +0 -0
- data/app/assets/images/content_types/file_extension_mov.png +0 -0
- data/app/assets/images/content_types/file_extension_mp2.png +0 -0
- data/app/assets/images/content_types/file_extension_mp4.png +0 -0
- data/app/assets/images/content_types/file_extension_mpeg.png +0 -0
- data/app/assets/images/content_types/file_extension_mpg.png +0 -0
- data/app/assets/images/content_types/file_extension_msi.png +0 -0
- data/app/assets/images/content_types/file_extension_mswmm.png +0 -0
- data/app/assets/images/content_types/file_extension_ogg.png +0 -0
- data/app/assets/images/content_types/file_extension_pdf.png +0 -0
- data/app/assets/images/content_types/file_extension_php.png +0 -0
- data/app/assets/images/content_types/file_extension_png.png +0 -0
- data/app/assets/images/content_types/file_extension_pps.png +0 -0
- data/app/assets/images/content_types/file_extension_ps.png +0 -0
- data/app/assets/images/content_types/file_extension_psd.png +0 -0
- data/app/assets/images/content_types/file_extension_pst.png +0 -0
- data/app/assets/images/content_types/file_extension_ptb.png +0 -0
- data/app/assets/images/content_types/file_extension_pub.png +0 -0
- data/app/assets/images/content_types/file_extension_qbb.png +0 -0
- data/app/assets/images/content_types/file_extension_qbw.png +0 -0
- data/app/assets/images/content_types/file_extension_qxd.png +0 -0
- data/app/assets/images/content_types/file_extension_ram.png +0 -0
- data/app/assets/images/content_types/file_extension_rar.png +0 -0
- data/app/assets/images/content_types/file_extension_rb.png +0 -0
- data/app/assets/images/content_types/file_extension_rm.png +0 -0
- data/app/assets/images/content_types/file_extension_rmvb.png +0 -0
- data/app/assets/images/content_types/file_extension_rtf.png +0 -0
- data/app/assets/images/content_types/file_extension_sea.png +0 -0
- data/app/assets/images/content_types/file_extension_ses.png +0 -0
- data/app/assets/images/content_types/file_extension_sit.png +0 -0
- data/app/assets/images/content_types/file_extension_sitx.png +0 -0
- data/app/assets/images/content_types/file_extension_ss.png +0 -0
- data/app/assets/images/content_types/file_extension_swf.png +0 -0
- data/app/assets/images/content_types/file_extension_tgz.png +0 -0
- data/app/assets/images/content_types/file_extension_thm.png +0 -0
- data/app/assets/images/content_types/file_extension_tif.png +0 -0
- data/app/assets/images/content_types/file_extension_tmp.png +0 -0
- data/app/assets/images/content_types/file_extension_torrent.png +0 -0
- data/app/assets/images/content_types/file_extension_ttf.png +0 -0
- data/app/assets/images/content_types/file_extension_txt.png +0 -0
- data/app/assets/images/content_types/file_extension_vcd.png +0 -0
- data/app/assets/images/content_types/file_extension_vob.png +0 -0
- data/app/assets/images/content_types/file_extension_wav.png +0 -0
- data/app/assets/images/content_types/file_extension_wma.png +0 -0
- data/app/assets/images/content_types/file_extension_wmv.png +0 -0
- data/app/assets/images/content_types/file_extension_wps.png +0 -0
- data/app/assets/images/content_types/file_extension_xls.png +0 -0
- data/app/assets/images/content_types/file_extension_xpi.png +0 -0
- data/app/assets/images/content_types/file_extension_zip.png +0 -0
- data/app/assets/images/female.png +0 -0
- data/app/assets/images/gear.png +0 -0
- data/app/assets/images/male.png +0 -0
- data/app/assets/images/new.png +0 -0
- data/app/assets/images/rotate_left.png +0 -0
- data/app/assets/images/rotate_right.png +0 -0
- data/app/assets/javascripts/the_storages/image_crop.js.coffee +69 -0
- data/app/assets/javascripts/the_storages/water_mark_switcher.js.coffee +17 -0
- data/app/assets/stylesheets/the_storages.css.scss +117 -0
- data/app/controllers/concerns/attached_files_actions.rb +37 -0
- data/app/controllers/concerns/the_storages_image_processor.rb +20 -0
- data/app/helpers/attached_files_list_helper.rb +115 -0
- data/app/helpers/file_size_helper.rb +9 -0
- data/app/models/concerns/act_as_attached_file.rb +69 -0
- data/app/models/concerns/act_as_storage.rb +7 -27
- data/app/models/concerns/attachment_processing.rb +46 -0
- data/app/models/concerns/has_attached_files.rb +14 -0
- data/app/models/concerns/image_manipulation.rb +63 -0
- data/app/models/concerns/storage_image_processing.rb +90 -0
- data/app/models/concerns/watermark_fu.rb +97 -0
- data/app/models/delayed_image_processor.rb +6 -0
- data/app/views/the_storages/_form.haml +10 -18
- data/app/views/the_storages/_list.haml +5 -39
- data/config/initializers/paperclip.rb +39 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/ru.yml +7 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20130101010101_attached_files.rb +29 -0
- data/db/migrate/20130101010102_change_storages.rb +2 -2
- data/fonts.txt +1342 -0
- data/lib/generators/the_storages/USAGE +1 -20
- data/lib/generators/the_storages/templates/the_storages.rb +10 -0
- data/lib/generators/the_storages/the_storages_generator.rb +4 -21
- data/lib/the_storages.rb +32 -2
- data/lib/the_storages/config.rb +32 -0
- data/lib/the_storages/version.rb +1 -1
- data/the_storages.gemspec +1 -0
- data/vendor/assets/images/Jcrop.gif +0 -0
- data/vendor/assets/javascripts/jquery.Jcrop.js +1694 -0
- data/vendor/assets/stylesheets/jquery.Jcrop.css +165 -0
- metadata +154 -15
- data/app/helpers/the_storages_helper.rb +0 -25
- data/app/models/uploaded_file.rb +0 -113
- data/app/views/the_storages/_new.haml +0 -36
- data/db/migrate/20130101010101_uploaded_files.rb +0 -25
- data/lib/generators/the_storages/views_generator.rb +0 -43
@@ -0,0 +1,37 @@
|
|
1
|
+
module AttachedFilesActions
|
2
|
+
def create
|
3
|
+
if params[:files]
|
4
|
+
attached_files_msg = []
|
5
|
+
attached_files_errors_msg = []
|
6
|
+
|
7
|
+
params[:files].each do |file|
|
8
|
+
attached_file = @storage.attached_files.new
|
9
|
+
attached_file.attachment = file
|
10
|
+
|
11
|
+
saved = attached_file.save
|
12
|
+
|
13
|
+
attached_files_msg.push attached_file.attachment_file_name if saved
|
14
|
+
attached_files_errors_msg.push attached_file.errors.first if !saved
|
15
|
+
end
|
16
|
+
|
17
|
+
flash[:notice] = attached_files_msg.join(', ')
|
18
|
+
flash[:error] = attached_files_errors_msg.join(', ')
|
19
|
+
|
20
|
+
redirect_to [request.referer, :files].join('#')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def watermark_switch
|
25
|
+
attachment = AttachedFile.find(params[:id])
|
26
|
+
attachment.toggle!(:watermark)
|
27
|
+
attachment.refresh_base_image
|
28
|
+
render nothing: true
|
29
|
+
end
|
30
|
+
|
31
|
+
def destroy
|
32
|
+
attachment = AttachedFile.find(params[:id])
|
33
|
+
attachment.destroy_processed_files
|
34
|
+
attachment.destroy
|
35
|
+
redirect_to [request.referer, :files].join('#')
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module TheStoragesImageProcessor
|
2
|
+
def rotate_left
|
3
|
+
attached_file = AttachedFile.where(id: params[:id]).first
|
4
|
+
attached_file.rotate_left
|
5
|
+
redirect_to [request.referer, :files].join('#')
|
6
|
+
end
|
7
|
+
|
8
|
+
def rotate_right
|
9
|
+
attached_file = AttachedFile.where(id: params[:id]).first
|
10
|
+
attached_file.rotate_right
|
11
|
+
redirect_to [request.referer, :files].join('#')
|
12
|
+
end
|
13
|
+
|
14
|
+
def crop_image
|
15
|
+
x = params
|
16
|
+
attached_file = AttachedFile.where(id: x[:image_id]).first
|
17
|
+
attached_file.crop_image(:main_preview, x[:x], x[:y], x[:w], x[:h], x[:img_w])
|
18
|
+
render text: attached_file.url(:main_preview, nocache: true)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# DOC:
|
4
|
+
# We use Helper Methods for tree building,
|
5
|
+
# because it's faster than View Templates and Partials
|
6
|
+
|
7
|
+
# SECURITY note
|
8
|
+
# Prepare your data on server side for rendering
|
9
|
+
# or use h.html_escape(node.content)
|
10
|
+
# for escape potentially dangerous content
|
11
|
+
module AttachedFilesListHelper
|
12
|
+
module Render
|
13
|
+
class << self
|
14
|
+
attr_accessor :h, :options
|
15
|
+
|
16
|
+
def render_node(h, options)
|
17
|
+
@h, @options = h, options
|
18
|
+
@node = options[:node]
|
19
|
+
|
20
|
+
"
|
21
|
+
<li data-node-id='#{ @node.id }'>
|
22
|
+
<div class='item'>
|
23
|
+
<i class='handle'></i>
|
24
|
+
#{ rotate_links }
|
25
|
+
<div class='preview_pic'>#{build_preview_pic}</div>
|
26
|
+
<div class='file_block'>
|
27
|
+
#{ show_link }
|
28
|
+
#{ url_input }
|
29
|
+
#{ watermark_switch }
|
30
|
+
#{ show_size }
|
31
|
+
</div>
|
32
|
+
#{ controls }
|
33
|
+
</div>
|
34
|
+
#{ children }
|
35
|
+
</li>
|
36
|
+
"
|
37
|
+
end
|
38
|
+
|
39
|
+
def current_host
|
40
|
+
h.request.protocol + h.request.host_with_port
|
41
|
+
end
|
42
|
+
|
43
|
+
def url_input
|
44
|
+
opts = {nocache: false, timestamp: false}
|
45
|
+
url = @node.is_image? ? @node.url(:base, opts) : @node.url(:original, opts)
|
46
|
+
"<div class='url_input'>URL: <input class='file_url' value='#{current_host + url}'></div>"
|
47
|
+
end
|
48
|
+
|
49
|
+
def show_size
|
50
|
+
"<div class='fsize'>#{@node.mb_size}</div>"
|
51
|
+
end
|
52
|
+
|
53
|
+
def watermark_switch
|
54
|
+
if @node.is_image?
|
55
|
+
link = if @node.watermark
|
56
|
+
"<span class='wm_on'>Вкл.</span>"
|
57
|
+
else
|
58
|
+
"<span class='wm_off'>Выкл.</span>"
|
59
|
+
end
|
60
|
+
|
61
|
+
"<div class='watermark_switcher'>Водный знак: #{link}</div>"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def rotate_links
|
66
|
+
if @node.is_image?
|
67
|
+
left = h.link_to '', h.rotate_left_url(@node), method: :patch, class: :left
|
68
|
+
right = h.link_to '', h.rotate_right_url(@node), method: :patch, class: :right
|
69
|
+
"<div class='rotate'>#{left} #{right}</div>"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_preview_pic
|
74
|
+
if @node.is_image?
|
75
|
+
src = @node.url(:preview)
|
76
|
+
url = @node.url(:base)
|
77
|
+
"<a href='#{url}'><img src='#{src}'></a>"
|
78
|
+
else
|
79
|
+
klass = @node.file_css_class
|
80
|
+
url = @node.url
|
81
|
+
"<a href='#{url}'><i class='#{klass}'></i></a>"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def show_link
|
86
|
+
node = options[:node]
|
87
|
+
ns = options[:namespace]
|
88
|
+
title_field = options[:title]
|
89
|
+
title = node.send(title_field)
|
90
|
+
url = @node.is_image? ? @node.url(:base) : @node.url
|
91
|
+
"<h4>#{ h.link_to(title, url)}</h4>"
|
92
|
+
end
|
93
|
+
|
94
|
+
def controls
|
95
|
+
node = options[:node]
|
96
|
+
|
97
|
+
edit_path = h.url_for(:controller => options[:klass].pluralize, :action => :edit, :id => node)
|
98
|
+
show_path = h.url_for(:controller => options[:klass].pluralize, :action => :show, :id => node)
|
99
|
+
|
100
|
+
"
|
101
|
+
<div class='controls'>
|
102
|
+
#{ h.link_to '', show_path, :class => :delete, :method => :delete, :data => { :confirm => 'Are you sure?' } }
|
103
|
+
</div>
|
104
|
+
"
|
105
|
+
end
|
106
|
+
|
107
|
+
def children
|
108
|
+
unless options[:children].blank?
|
109
|
+
"<ol class='nested_set'>#{ options[:children] }</ol>"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ActAsAttachedFile
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include AttachmentProcessing
|
5
|
+
include StorageImageProcessing
|
6
|
+
|
7
|
+
included do
|
8
|
+
IMAGE_EXTS = %w[jpg jpeg pjpeg png x-png gif bmp]
|
9
|
+
IMAGE_CONTENT_TYPES = IMAGE_EXTS.map{ |e| "image/#{e}" }
|
10
|
+
|
11
|
+
belongs_to :user
|
12
|
+
belongs_to :storage, polymorphic: true
|
13
|
+
acts_as_nested_set scope: [:user_id, :storage_id, :storage_type]
|
14
|
+
include TheSortableTree::Scopes
|
15
|
+
|
16
|
+
before_validation :generate_file_name, on: :create
|
17
|
+
after_create :recalculate_storage_counters!
|
18
|
+
after_destroy :recalculate_storage_counters!
|
19
|
+
scope :images, ->{ where(attachment_content_type: IMAGE_CONTENT_TYPES) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def file_css_class
|
23
|
+
'f_' + TheStorages.file_ext(attachment_file_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
# HELPERS
|
27
|
+
def title
|
28
|
+
attachment_file_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def file_name
|
32
|
+
TheStorages.file_name(attachment_file_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def content_type
|
36
|
+
attachment_content_type
|
37
|
+
end
|
38
|
+
|
39
|
+
def mb_size
|
40
|
+
FileSizeHelper.mb_size(attachment_file_size)
|
41
|
+
end
|
42
|
+
|
43
|
+
def path style = nil
|
44
|
+
attachment.path(style)
|
45
|
+
end
|
46
|
+
|
47
|
+
def url style = nil, opts = {}
|
48
|
+
url = attachment.url(style, opts)
|
49
|
+
return url unless opts[:nocache]
|
50
|
+
rnd = (rand*1000000).to_i.to_s
|
51
|
+
url =~ /\?/ ? (url + rnd) : (url + '?' + rnd)
|
52
|
+
end
|
53
|
+
|
54
|
+
# BASE HELPERS
|
55
|
+
def is_image?
|
56
|
+
IMAGE_EXTS.include? TheStorages.file_ext(attachment_file_name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate_file_name
|
60
|
+
file_name = attachment.instance_read(:file_name)
|
61
|
+
file_name = TheStorages.slugged_file_name(file_name)
|
62
|
+
attachment.instance_write :file_name, file_name
|
63
|
+
end
|
64
|
+
|
65
|
+
# CALLBACKS
|
66
|
+
def recalculate_storage_counters!
|
67
|
+
storage.recalculate_storage_counters!
|
68
|
+
end
|
69
|
+
end
|
@@ -2,35 +2,15 @@ module ActAsStorage
|
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
4
|
included do
|
5
|
-
has_many :
|
6
|
-
|
7
|
-
before_update :recalculate_files_data
|
8
|
-
after_update :recalculate_files_data_for_user
|
9
|
-
after_destroy :recalculate_files_data_for_user
|
5
|
+
has_many :attached_files, as: :storage
|
10
6
|
end
|
11
7
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
self.files_size = sum
|
18
|
-
self.files_count = files.size
|
19
|
-
end
|
20
|
-
|
21
|
-
def recalculate_files_data_for_user
|
22
|
-
user = self.user
|
23
|
-
storages = user.storages.active | user.recipes.active | user.pages.active | user.articles.active
|
24
|
-
files_size = 0
|
25
|
-
files_count = 0
|
26
|
-
|
27
|
-
storages.each do |s|
|
28
|
-
files_size += s.files_size
|
29
|
-
files_count += s.files_count
|
30
|
-
end
|
8
|
+
def recalculate_storage_counters!
|
9
|
+
af = attached_files.pluck(:attachment_file_size)
|
10
|
+
self.storage_files_count = af.count
|
11
|
+
self.storage_files_size = af.sum
|
12
|
+
save
|
31
13
|
|
32
|
-
user.
|
33
|
-
user.files_count = files_count
|
34
|
-
user.save(:validation => false)
|
14
|
+
self.try(:user).try(:recalculate_all_attached_files!)
|
35
15
|
end
|
36
16
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module AttachmentProcessing
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
attr_accessor :image_processing
|
6
|
+
before_create :set_processing_flags
|
7
|
+
after_commit :delayed_file_processing
|
8
|
+
|
9
|
+
has_attached_file :attachment,
|
10
|
+
default_url: ":rails_root/public/system/uploads/default/:style-missing.jpg",
|
11
|
+
path: ":rails_root/public/system/storages/:storage_type/:storage_id/:style/:filename",
|
12
|
+
url: "/system/storages/:storage_type/:storage_id/:style/:filename"
|
13
|
+
|
14
|
+
validates_attachment_size :attachment,
|
15
|
+
in: 10.bytes..5.megabytes,
|
16
|
+
message: I18n.translate('the_storages.validation.attachment_file_size')
|
17
|
+
|
18
|
+
validates :attachment_file_name,
|
19
|
+
uniqueness: {
|
20
|
+
scope: [:user_id, :storage_type, :storage_id],
|
21
|
+
message: I18n.translate('the_storages.validation.uniq_attachment_file_name')
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_processing_flags
|
26
|
+
if is_image?
|
27
|
+
self.processing = :processing
|
28
|
+
self.image_processing = true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# DELAYED JOB
|
33
|
+
def delayed_file_processing
|
34
|
+
if is_image? && image_processing
|
35
|
+
self.image_processing = false
|
36
|
+
job = DelayedImageProcessor.new(self)
|
37
|
+
|
38
|
+
job.perform
|
39
|
+
# Delayed::Job.enqueue job, queue: :image_processing, run_at: Proc.new { 10.seconds.from_now }
|
40
|
+
else
|
41
|
+
# if it's not image
|
42
|
+
# Upload file and recalculate
|
43
|
+
recalculate_storage_counters!
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module HasAttachedFiles
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
has_many :all_attached_files, class_name: :AttachedFile, foreign_key: :user_id
|
6
|
+
end
|
7
|
+
|
8
|
+
def recalculate_all_attached_files
|
9
|
+
af = all_attached_files.pluck(:attachment_file_size)
|
10
|
+
self.all_attached_files_count = af.count
|
11
|
+
self.all_attached_files_size = af.sum
|
12
|
+
save
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module ImageManipulation
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
# HELPERS
|
5
|
+
def landscape? image
|
6
|
+
image[:width] > image[:height]
|
7
|
+
end
|
8
|
+
|
9
|
+
def portrait? image
|
10
|
+
image[:width] < image[:height]
|
11
|
+
end
|
12
|
+
|
13
|
+
# Fu
|
14
|
+
def rotate_image src, dest, angle
|
15
|
+
img = MiniMagick::Image.open(src)
|
16
|
+
img.rotate(angle)
|
17
|
+
img.write(dest)
|
18
|
+
end
|
19
|
+
|
20
|
+
def rotate_attached_image angle
|
21
|
+
src = path
|
22
|
+
rotate_image(src,src,angle)
|
23
|
+
refresh_base_image
|
24
|
+
end
|
25
|
+
|
26
|
+
def rotate_left
|
27
|
+
rotate_attached_image "-90"
|
28
|
+
end
|
29
|
+
|
30
|
+
def rotate_right
|
31
|
+
rotate_attached_image "90"
|
32
|
+
end
|
33
|
+
|
34
|
+
def resize_to_larger_side image, side_size
|
35
|
+
if image[:width] > side_size.to_i
|
36
|
+
landscape?(image) ?
|
37
|
+
image.resize("#{side_size}x") :
|
38
|
+
image.resize("x#{side_size}")
|
39
|
+
end
|
40
|
+
|
41
|
+
image
|
42
|
+
end
|
43
|
+
|
44
|
+
def resize_to_larger_side! src, side_size
|
45
|
+
image = MiniMagick::Image.open(src)
|
46
|
+
image = resize_to_larger_side(image, side_size)
|
47
|
+
image.write src
|
48
|
+
end
|
49
|
+
|
50
|
+
# IMAGE CROP
|
51
|
+
def crop_image src, dest, x0 = 0, y0 = 0, w = 100, h = 100, scale = 1
|
52
|
+
image = MiniMagick::Image.open src
|
53
|
+
|
54
|
+
x_shift = (x0.to_f * scale).to_i
|
55
|
+
y_shift = (y0.to_f * scale).to_i
|
56
|
+
|
57
|
+
w = (w.to_f * scale).to_i
|
58
|
+
h = (h.to_f * scale).to_i
|
59
|
+
|
60
|
+
image.crop "#{w}x#{h}+#{x_shift}+#{y_shift}"
|
61
|
+
image.write dest
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module StorageImageProcessing
|
3
|
+
include WatermarkFu
|
4
|
+
include ImageManipulation
|
5
|
+
|
6
|
+
def draw_watermark
|
7
|
+
return false unless need_watermark?
|
8
|
+
build_watermarks
|
9
|
+
put_watermark_on_base_image
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_base_images
|
13
|
+
resize_src_image
|
14
|
+
refresh_base_image
|
15
|
+
|
16
|
+
# set process state
|
17
|
+
src_size = File.size?(path)
|
18
|
+
update(processing: :finished, attachment_file_size: src_size)
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_img_dir_path path
|
22
|
+
_path = path.split('/')[0...-1].join('/')
|
23
|
+
FileUtils.mkdir_p _path
|
24
|
+
end
|
25
|
+
|
26
|
+
# IMAGE PROCESSING
|
27
|
+
def prepare_image src, dest, larger_side
|
28
|
+
image = MiniMagick::Image.open src
|
29
|
+
image.auto_orient
|
30
|
+
resize_to_larger_side(image, larger_side)
|
31
|
+
image.strip
|
32
|
+
create_img_dir_path(dest)
|
33
|
+
image.write(dest)
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_square_image src, dest, side = 100
|
37
|
+
image = MiniMagick::Image.open src
|
38
|
+
|
39
|
+
min_size = image[:width]
|
40
|
+
shift = { x: 0, y: 0}
|
41
|
+
|
42
|
+
if landscape?(image)
|
43
|
+
min_size = image[:height]
|
44
|
+
shift[:x] = (image[:width] - min_size) / 2
|
45
|
+
elsif portrait?(image)
|
46
|
+
min_size = image[:width]
|
47
|
+
shift[:y] = (image[:height] - min_size) / 2
|
48
|
+
end
|
49
|
+
|
50
|
+
x0 = shift[:x]
|
51
|
+
y0 = shift[:y]
|
52
|
+
w = h = min_size
|
53
|
+
|
54
|
+
image.crop "#{w}x#{h}+#{x0}+#{y0}"
|
55
|
+
image.resize "#{side}x#{side}!"
|
56
|
+
|
57
|
+
create_img_dir_path(dest)
|
58
|
+
image.write dest
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_correct_preview
|
62
|
+
src = path
|
63
|
+
preview = path :preview
|
64
|
+
build_square_image(src, preview, 100)
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_base_image
|
68
|
+
src = path
|
69
|
+
base = path :base
|
70
|
+
prepare_image(src, base, TheStorages.config.base_larger_side)
|
71
|
+
end
|
72
|
+
|
73
|
+
def refresh_base_image
|
74
|
+
build_base_image
|
75
|
+
build_correct_preview
|
76
|
+
draw_watermark
|
77
|
+
end
|
78
|
+
|
79
|
+
def resize_src_image
|
80
|
+
src = path
|
81
|
+
prepare_image(src, src, TheStorages.config.original_larger_side)
|
82
|
+
end
|
83
|
+
|
84
|
+
def destroy_processed_files
|
85
|
+
base = path :base
|
86
|
+
preview = path :preview
|
87
|
+
|
88
|
+
FileUtils.rm([base, preview], force: true)
|
89
|
+
end
|
90
|
+
end
|