/
attacher.rb
182 lines (157 loc) · 4.32 KB
/
attacher.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
module Refile
# @api private
class Attacher
attr_reader :record, :name, :cache, :store, :options, :errors, :type, :valid_extensions, :valid_content_types
attr_accessor :remove
Presence = ->(val) { val if val != "" }
def initialize(record, name, cache:, store:, raise_errors: true, type: nil, extension: nil, content_type: nil)
@record = record
@name = name
@raise_errors = raise_errors
@cache = Refile.backends.fetch(cache.to_s)
@store = Refile.backends.fetch(store.to_s)
@type = type
@valid_extensions = [extension].flatten if extension
@valid_content_types = [content_type].flatten if content_type
@valid_content_types ||= Refile.types.fetch(type).content_type if type
@errors = []
@metadata = {}
end
def id
Presence[read(:id)]
end
def size
Presence[@metadata[:size] || read(:size)]
end
def filename
Presence[@metadata[:filename] || read(:filename)]
end
def content_type
Presence[@metadata[:content_type] || read(:content_type)]
end
def cache_id
Presence[@metadata[:id]]
end
def basename
if filename and extension
::File.basename(filename, "." << extension)
else
filename
end
end
def extension
if filename
Presence[::File.extname(filename).sub(/^\./, "")]
elsif content_type
type = MIME::Types[content_type][0]
type.extensions[0] if type
end
end
def get
if cache_id
cache.get(cache_id)
elsif id
store.get(id)
end
end
def set(value)
if value.is_a?(String)
retrieve!(value)
else
cache!(value)
end
end
def retrieve!(value)
@metadata = JSON.parse(value, symbolize_names: true) || {}
write_metadata if cache_id
rescue JSON::ParserError
end
def cache!(uploadable)
@metadata = {
size: uploadable.size,
content_type: Refile.extract_content_type(uploadable),
filename: Refile.extract_filename(uploadable)
}
if valid?
@metadata[:id] = cache.upload(uploadable).id
write_metadata
elsif @raise_errors
raise Refile::Invalid, @errors.join(", ")
end
end
def download(url)
unless url.to_s.empty?
response = RestClient::Request.new(method: :get, url: url, raw_response: true).execute
@metadata = {
size: response.file.size,
filename: ::File.basename(url),
content_type: response.headers[:content_type]
}
if valid?
@metadata[:id] = cache.upload(response.file).id
write_metadata
elsif @raise_errors
raise Refile::Invalid, @errors.join(", ")
end
end
rescue RestClient::Exception
@errors = [:download_failed]
raise if @raise_errors
end
def store!
if remove?
delete!
write(:id, nil)
elsif cache_id
file = store.upload(get)
delete!
write(:id, file.id)
end
write_metadata
@metadata = {}
end
def delete!
cache.delete(cache_id) if cache_id
store.delete(id) if id
@metadata = {}
end
def accept
if valid_content_types
valid_content_types.join(",")
elsif valid_extensions
valid_extensions.map { |e| ".#{e}" }.join(",")
end
end
def remove?
remove and remove != "" and remove !~ /\A0|false$\z/
end
def present?
not @metadata.empty?
end
def valid?
@errors = []
@errors << :invalid_extension if valid_extensions and not valid_extensions.include?(extension)
@errors << :invalid_content_type if valid_content_types and not valid_content_types.include?(content_type)
@errors << :too_large if cache.max_size and size and size >= cache.max_size
@errors.empty?
end
def data
@metadata if valid?
end
private
def read(column)
m = "#{name}_#{column}"
value ||= record.send(m) if record.respond_to?(m)
value
end
def write(column, value)
m = "#{name}_#{column}="
record.send(m, value) if record.respond_to?(m) and not record.frozen?
end
def write_metadata
write(:size, size)
write(:content_type, content_type)
write(:filename, filename)
end
end
end