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



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 122

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



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 137

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



213
214
215
216
217
218
219
220
221
222
223
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 213

def self.get_attachments(att_doc)
  return nil unless att_doc
  custom_md = att_doc['md_attachments']
  esc_couch_md = att_doc['_attachments']
  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



118
119
120
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 118

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.


164
165
166
167
168
169
170
171
172
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
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 164

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



226
227
228
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 226

def get_attachments
  self.class.get_attachments(self) 
end

#remove_attachment(attachment_names) ⇒ Object



230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/glue_envs/couchrest/couchrest_attachment_handler.rb', line 230

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