class Sdk4me::Attachments
Constants
- FILENAME_TEMPLATE
- S3_PROVIDER
Public Class Methods
new(client, path)
click to toggle source
# File lib/sdk4me/client/attachments.rb, line 6 def initialize(client, path) @client = client @path = path end
Public Instance Methods
upload_attachments!(data)
click to toggle source
Upload attachments and replace the data inline with the uploaded attachments info.
To upload field attachments:
* data[:note_attachments] = ['/tmp/test.doc', '/tmp/test.log']
To upload inline images:
* data[:note] containing text referring to inline images in data[:note_attachments] by their array index, with the index being zero-based. Text can only refer to inline images in its own attachments collection. For example: data = { note: "Hello [note_attachments: 0] and [note_attachments: 1]", note_attachments: ['/tmp/jip.png', '/tmp/janneke.png'], ... }
After calling this method the data that will be posted to update the 4me record would look similar to:
data = { note: "Hello  and ", note_attachments: [ { key: 'storage/abc/adjhajdhjaadf.png', filesize: 12345, inline: true }, { key: 'storage/abc/fskdhakjfkjdssdf.png'], filesize: 98765, inline: true } ], ... }
# File lib/sdk4me/client/attachments.rb, line 40 def upload_attachments!(data) # Field attachments field_attachments = [] data.each do |field, value| next unless field.to_s.end_with?('_attachments') next unless value.is_a?(Enumerable) && value.any? value.map! { |attachment| upload_attachment(attachment) }.compact! field_attachments << field if value.any? end # Rich text inline attachments field_attachments.each do |field_attachment| field = field_attachment.to_s.sub(/_attachments$/, '') value = data[field.to_sym] || data[field] next unless value.is_a?(String) value.gsub!(/\[#{field_attachment}:\s?(\d+)\]/) do |match| idx = Regexp.last_match(1).to_i attachment = data[field_attachment][idx] if attachment attachment[:inline] = true "" # magic markdown for inline attachments else match end end end end
Private Instance Methods
raise_error(message)
click to toggle source
# File lib/sdk4me/client/attachments.rb, line 72 def raise_error(message) @client.logger.error { message } raise Sdk4me::UploadFailed, message end
send_file(uri, params, basic_auth_header = {})
click to toggle source
# File lib/sdk4me/client/attachments.rb, line 134 def send_file(uri, params, basic_auth_header = {}) params = { 'Content-Type': MIME::Types.type_for(params[:key])[0] || MIME::Types['application/octet-stream'][0] }.merge(params) data, header = Sdk4me::Multipart::Post.prepare_query(params) ssl, domain, port, path = @client.send(:ssl_domain_port_path, uri) request = Net::HTTP::Post.new(path, basic_auth_header.merge(header)) request.body = data @client.send(:_send, request, domain, port, ssl) end
storage()
click to toggle source
# File lib/sdk4me/client/attachments.rb, line 77 def storage @storage ||= @client.get('/attachments/storage').json.with_indifferent_access end
upload_attachment(attachment)
click to toggle source
Upload a single attachment and return the data that should be submitted back to 4me. Returns nil and provides an error in case the attachment upload failed.
# File lib/sdk4me/client/attachments.rb, line 84 def upload_attachment(attachment) return nil unless attachment provider = storage[:provider] raise 'No provider found' unless provider # attachment is already a file or we need to open the file from disk unless attachment.respond_to?(:path) && attachment.respond_to?(:read) raise "file does not exist: #{attachment}" unless File.exist?(attachment) attachment = File.open(attachment, 'rb') end key_template = storage[provider][:key] key = key_template.sub(FILENAME_TEMPLATE, File.basename(attachment.path)) key = if provider == S3_PROVIDER upload_to_s3(key, attachment) else upload_to_4me_local(key, attachment) end # return the values for the attachments param { key: key, filesize: File.size(attachment.path) } rescue StandardError => e raise_error("Attachment upload failed: #{e.message}") end
upload_to_4me_local(key, attachment)
click to toggle source
Upload the file directly to 4me local storage
# File lib/sdk4me/client/attachments.rb, line 126 def upload_to_4me_local(key, attachment) uri = storage[:upload_uri] response = send_file(uri, storage[:local].merge({ file: attachment }), @client.send(:expand_header)) raise "4me upload to #{uri} for #{key} failed: #{response.message}" unless response.valid? JSON.parse(response.body)['key'] end
upload_to_s3(key, attachment)
click to toggle source
Upload the file to AWS S3 storage
# File lib/sdk4me/client/attachments.rb, line 113 def upload_to_s3(key, attachment) uri = storage[:upload_uri] response = send_file(uri, storage[:s3].merge({ file: attachment })) # this is a bit of a hack, but Amazon S3 returns only XML :( xml = response.body || '' error = xml[%r{<Error>.*<Message>(.*)</Message>.*</Error>}, 1] raise "AWS S3 upload to #{uri} for #{key} failed: #{error}" if error xml[%r{<Key>(.*)</Key>}, 1] end