I am trying to build a python-eve REST API with mysql backend and I would like to have a custom mediastorage backend. Basicly I want the filenames saved into database and files in filesystem.
Here is a draft of the mediastorage based on the GridFS in the core:
class CustomMediaStorage(MediaStorage):
def __init__(self, app=None):
super(CustomMediaStorage, self).__init__(app)
self.validate()
def validate(self):
if self.app is None:
raise TypeError('Application object cannot be None')
if not isinstance(self.app, Flask):
raise TypeError('Application object must be a Eve application')
def get(self, path, resource=None):
pprint(path)
_file = None
try:
_file = open(path, 'r')
except:
pass
return _file
def post(self, content, filename=None, content_type=None, resource=None):
pprint('post')
if(filename):
path = 'var/www/koodit/upload/'+filename
try:
_file = open(path, 'w')
_file.write(content)
_file.close()
except:
pass
return path
My specific problem here is that while the class catches the get-method the post-method does not seem to be able even to print out the comment.
Calling the media storage this way:
app = Eve(data=SQL,settings=SETTINGS, media=CustomMediaStorage)
From client side I tried to send the image as base64.
"file was expected, got 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCEUGhvdG9zaG9wIDMu...
instead.",
Related
I'm integrating with a third party ID verification provider. Once the ID verification checks have run a report is generated, which I can access with a get request.
The response is binary text (screenshot attached), which I want to save to a PDF file.
Function:
def generate_pdf
resources = "applicants/61f84499b7b92f00014d5c6d/summary/report?report=applicantReport"
response = RestClient.get(request_env_url(resources), signed_header(resources, nil, 'GET', 'application/pdf'))
puts response
end
How do I take the binary response, create a new file and add the binary into that file in a friendly and readable format?
If you can access a filesystem, you might just want to write that data to a file:
File.open("thing.pdf", "wb") { |f| f.write response }
Rails 5.1 -
Ruby 2.3.4 -
AWS S3 - Carrierwave & Minimagick
I would like to import a CSV file to my Rails app and also upload Images with each record.
The images are URL's from a current AWS S3 Bucket. I am able to upload from my local drive but only in development.
def self.import(file)
CSV.foreach(file.path, headers: true, header_converters: :symbol) do |row|
Model.find_or_create_by(name: row[:name]) do |m|
m.name = row[:name]
m.description = row[:description]
m.image = URI.parse(row[:image])
m.summary = row[:summary]
end
end
end
The CSV is simply
name,descripton,image,summary
Test,Test-Description,https://s3.amazonaws.com/main/production/model/7/image/image-formated.jpg,Test-Summary
Though whenever I try and upload on my live server. The images are not processed. How can I reference and upload the images correctly?
I can't load the URL that you have but it should work with something like:
m.image = URI.parse(row[:image]).open
This will return a tempfile which Rails will associate to the model.
Background:
URI.parse() returns URI::HTTPS the url encoded URI for example:
URI.parse('https://google.com/search?q=test this')
# => #<URI::HTTPS https://google.com/search?q=test%20this> # where %20 is a url encoded space
So assuming your model expects an image file, you want to open and save the file rather than the URI. If this does not solve this, please share the config for your model
How to get URL uploaded doc on drop box and how to store this URL our data base.
This is the code :
def passport_upload
app_key = ENV['APP_DROPBOX_APP_KEY_DEVELOPMENT']
app_secret = ENV['APP_DROPBOX_APP_SECRET_DEVELOPMENT']
flow = DropboxOAuth2FlowNoRedirect.new(app_key, app_secret)
authorize_url = flow.start()
client=DropboxClient.new(ENV['APP_DROPBOX_ACCESS_TOKEN_DEVELOPMENT'])
file = open(params[:doc])
file_name = params[:doc].original_filename
response = client.put_file(file_name, file)
end
If you want the URL to retrieve it using authorized access, you should appending the path returned in the metadata response to https://content.dropboxapi.com/1/files/auto/ (per https://www.dropbox.com/developers-v1/core/docs#files-GET).
If you want to publicly share it and get a public URL you will have to
make a call to share it (per https://www.dropbox.com/developers-v1/core/docs#shares)
client.shares(response.path)
I a writing a Rails API, with help of aws-sdk-ruby, which retrieves a file from AWS and returns in the response of API. Can I get somehow file stream in response of object.get, which I can directly return from the Rails API.
s3 = Aws::S3::Resource.new
bucket_name = "my_bucket"
bucket = s3.bucket(bucket_name)
object = bucket.object("a/b/my.pdf")
Rails.logger.info 'Downloading file to AWS'
downloaded_data = object.get({})
send_data(downloaded_data,
:filename => "my.pdf",
:type => "mime/type"
)
But it does not return file.
One option I know is to first save the file in local using this line:
object.get(response_target: '/tmp/my.pdf')
Than I can return this file but is there a way to skip this step and directly return the response of object.get without saving in local.
I can not use this solution as my URL are not public and I am just creating a REST API.
I got screen like following when I tried this solution.
As of now what I am doing is getting a URL from the object like this:
url = object.presigned_url(:get, expires_in: 3600)
and using following code to send the response:
data = open(url)
send_data data.read, filename: file_name, type: "mime/type"
In my app, I have a requirement that is stumping me.
I have a file stored in S3, and when a user clicks on a link in my app, I log in the DB they've clicked the link, decrease their 'download credit' allowance by one and then I want to prompt the file for download.
I don't simply want to redirect the user to the file because it's stored in S3 and I don't want them to have the link of the source file (so that I can maintain integrity and access)
It looks like send_file() wont work with a remote source file, anyone recommend a gem or suitable code which will do this?
You would need to stream the file content to the user while reading it from the S3 bucket/object.
If you use the AWS::S3 library something like this may work:
send_file_headers!( :length=>S3Object.about(<s3 object>, <s3 bucket>)["content-length"], :filename=><the filename> )
render :status => 200, :text => Proc.new { |response, output|
S3Object.stream(<s3 object>, <s3 bucket>) do |chunk|
output.write chunk
end
}
This code is mostly copied form the send_file code which by itself works only for local files or file-like objects
N.B. I would anyhow advise against serving the file from the rails process itself. If possible/acceptable for your use case I'd use an authenticated GET to serve the private data from the bucket.
Using an authenticated GET you can keep the bucket and its objects private, while allowing temporary permission to read a specific object content by crafting a URL that includes an authentication signature token. The user is simply redirected to the authenticated URL, and the token can be made valid for just a few minutes.
Using the above mentioned AWS::S3 you can obtain an authenticated GET url in this way:
time_of_exipry = Time.now + 2.minutes
S3Object.url_for(<s3 object>, <s3 bucket>,
:expires => time_of_exipry)
Full image download method using temp file (tested rails 3.2):
def download
#image = Image.find(params[:image_id])
open(#image.url) {|img|
tmpfile = Tempfile.new("download.jpg")
File.open(tmpfile.path, 'wb') do |f|
f.write img.read
end
send_file tmpfile.path, :filename => "great-image.jpg"
}
end
You can read the file from S3 and write it locally to a non-public directory, then use X-Sendfile (apache) or X-Accel-Redirect (nginx) to serve the content.
For nginx you would include something like the following in your config:
location /private {
internal;
alias /path/to/private/directory/;
}
Then in your rails controller, you do the following:
response.headers['Content-Type'] = your_content_type
response.headers['Content-Disposition'] = "attachment; filename=#{your_file_name}"
response.headers['Cache-Control'] = "private"
response.headers['X-Accel-Redirect'] = path_to_your_file
render :nothing=>true
A good writeup of the process is here