Class: CouchrestAttachment

Inherits:
CouchRest::ExtendedDocument
  • Object
show all
Defined in:
lib/glue_envs/couchrest/couchrest_attachment_handler.rb

Overview

Converts from Tinkit attachment format to closer to the metal couchrest/CouchDB attachment format. The reason this is needed is because CouchDB cannot support custom metadata for attachments. So custom metadata is held in the CouchrestAttachment document. This document will also hold the attachments and its built in metadata (such as content-type and modified times Attachment structure: attachments =>{ attachment_1 => { ‘data1’ => raw attachment data1,

                  'md1' => combined attachment metadata1 },
attachment_2 => { 'data2' => raw attachment data2,
                  'md2' => combined attachment metadata2 }

}

Constant Summary collapse

CouchDBAttachParams =

CouchDB attachment metadata parameters supported by CouchrestAttachment

['content_type', 'stub'  ]
AttachmentID =

changing this will result in existing persisted data being lost (unless the persisted data is updated as well)

"_attachments"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.add_attachment_package(doc_id, attach_class, attachments) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 131

def self.add_attachment_package(doc_id, attach_class, attachments)
  raise "No class definition provided for attachments" unless attach_class
  raise "No id found for the document" unless doc_id #bufs_node._model_metadata[:_id]
  raise "No attachments provided for attaching" unless attachments
  att_doc_id = self.uniq_att_doc_id(doc_id)
  att_doc = self.get(att_doc_id)
  rtn = if att_doc
    self.update_attachment_package(att_doc, attachments)
  else
    self.create_attachment_package(att_doc_id, attach_class, attachments)
  end
  return rtn
end

.create_attachment_package(att_doc_id, attach_class, attachments) ⇒ Object

Create an attachment for a particular BUFS document



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 146

def self.create_attachment_package(att_doc_id, attach_class, attachments)
  raise "No class definition provided for attachments" unless attach_class
  raise "No id found for the document" unless att_doc_id 
  raise "No attachments provided for attaching" unless attachments
  
  sorted_attachments = CouchrestAttachmentHelpers.sort_attachment_data(attachments)
   = {'_id' => att_doc_id, 'md_attachments' => sorted_attachments['cust_md_by_name']}
  att_doc = attach_class.new()
  att_doc.save
 
  sorted_attachments['att_md_by_name'].each do |att_name, params|
    esc_att_name = TkEscape.escape(att_name)
    att_doc.put_attachment(esc_att_name, sorted_attachments['data_by_name'][esc_att_name],params)
  end
  
  #returns the updated document from the database
  return self.get(att_doc_id)
end

.get_attachments(att_doc) ⇒ Object

retrieves document attachments for a particular document



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 222

def self.get_attachments(att_doc)
  return nil unless att_doc
  custom_md = att_doc['md_attachments']
  esc_couch_md = att_doc['_attachments']
  md_no_att = custom_md && !esc_couch_md
  att_no_md = esc_couch_md && !custom_md
  raise "DB Record corrupted? Attachment metadata exists,"\
        " but no attachments for #{att_doc['_id'].inspect}" if md_no_att 
  raise "DB Record corrupted? Attachments exist, but no metadata"\
        " is associated with it for #{att_doc['_id'].inspect}" if att_no_md
  couch_md = CouchrestAttachmentHelpers.unescape_names_in_attachments(esc_couch_md)
  if custom_md.keys.sort != couch_md.keys.sort
    raise "data integrity error, attachment metadata inconsistency\n"\
           "in memory: #{custom_md.inspect} \n persisted: #{couch_md.inspect}"
  end
  (attachment_data = custom_md.dup).merge(couch_md) {|k,v_custom, v_couch| v_custom.merge(v_couch)}
end

.uniq_att_doc_id(doc_id) ⇒ Object

create the attachment document id to be used



127
128
129
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 127

def self.uniq_att_doc_id(doc_id)
  uniq_id = doc_id + AttachmentID if doc_id#bufs_node.class.attachment_base_id 
end

.update_attachment_package(att_doc, new_attachments) ⇒ Object

Update the attachment data for a particular BUFS document

Important Note: Currently existing data is only updated if new data has been modified more recently than the existing data.


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 173

def self.update_attachment_package(att_doc, new_attachments)
  existing_attachments = att_doc.get_attachments
  most_recent_attachment = {}
  if existing_attachments
    new_attachments.each do |new_att_name, new_data|
    esc_new_att_name = TkEscape.escape(new_att_name)
      working_doc = att_doc.class.get(att_doc['_id'])
      if existing_attachments.keys.include? esc_new_att_name
        #filename already exists as an attachment
        fresh_attachment =self.find_most_recent_attachment(existing_attachments[esc_new_att_name], new_attachments[new_att_name]['md'])
        most_recent_attachment[esc_new_att_name] = fresh_attachment
        
        #re-add the if statement to prevent old from overwriting newer files
        ###if most_recent_attachment[esc_new_att_name] != existing_attachments[esc_new_att_name]
          #update that file and metadata
          sorted_attachments = CouchrestAttachmentHelpers.sort_attachment_data(esc_new_att_name => new_data)
          #update doc
          working_doc['md_attachments'] = working_doc['md_attachments'].merge(sorted_attachments['cust_md_by_name'])
          #update attachments
          working_doc.save
          #Add Couch attachment data
          att_data = sorted_attachments['data_by_name'][esc_new_att_name]
          att_md =  sorted_attachments['att_md_by_name'][esc_new_att_name]
          working_doc.put_attachment(esc_new_att_name, att_data,att_md)
        ###else
          #do anything here?
          #puts "Warning, didn't update the attachment because current attachment is older than present one"
        ###end
      else #filename does not exist in attachment
        #puts "Attachment Name not found in Attachment Document, adding #{esc_new_att_name}"
        sorted_attachments = CouchrestAttachmentHelpers.sort_attachment_data(esc_new_att_name => new_data)
        #update doc
        working_doc['md_attachments'] = working_doc['md_attachments'].merge(sorted_attachments['cust_md_by_name'])
        #update attachments
        working_doc.save
        #Add Couch attachment data
        att_data = sorted_attachments['data_by_name'][esc_new_att_name]
        att_md =  sorted_attachments['att_md_by_name'][esc_new_att_name]
        working_doc.put_attachment(esc_new_att_name, att_data,att_md)
        #working_doc does not have attachment
        
      end
      
    end
  end
  return att_doc.class.get(att_doc['_id'])
end

Instance Method Details

#get_attachmentsObject

retrieves document attachments for this document



241
242
243
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 241

def get_attachments
  self.class.get_attachments(self) 
end

#remove_attachment(attachment_names) ⇒ Object



245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 245

def remove_attachment(attachment_names)
  attachment_names = [attachment_names].flatten
  attachment_names.each do |att_name|
    att_name = TkEscape.escape(att_name)
    self['md_attachments'].delete(att_name)
    self['_attachments'].delete(att_name)
  end
  resp = self.save
  atts = self.class.get_attachments(self)
  raise "Remove Attachment Operation Failed with response: #{resp.inspect}" unless resp == true
  self
end