スマホとか含めクライアント問わずアップロードしたファイルを、ローカルサーバに取り込む必要があったので、S3を使った忘備録です。
heroku上へのwebアプリの構築法は下記を参考にしてください。
twilioとSendGridとherokuでキャリアメール代替プッシュ通知
herokuでflaskアプリを実行するための環境変数設定
(venv)$heroku config:set FLASK_APP=upload.py
(venv)$heroku config:set FLASK_CONFIG=heroku
AWS S3にアクセスするための環境変数設定
S3のバケット名と、IAMで、ユーザ作って、security credentialsで作ったaccess key
(venv)$heroku config:set S3BUCKET=S3バケット名
(venv)$heroku config:set AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxx
(venv)$heroku config:set AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
webページのbasic認証パスワードを環境変数で設定
ユーザ名はソースコードの中に埋め殺し(user)
(venv)$heroku config:set USER_PW=xxxxxxxx
ソースコード他
requirements.txt
boto==2.49.0
Click==7.0
Flask==1.1.1
Flask-HTTPAuth==3.3.0
gunicorn==19.9.0
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
Werkzeug==0.16.0
Procfile
web: gunicorn upload:app --timeout 15 --keep-alive 5 --log-level debug
ソースコード
upload.py
from flask import Flask, render_template, request, jsonify
from werkzeug import secure_filename
from flask_httpauth import HTTPDigestAuth
import boto
import os
'''
アプリコンストラクタ
'''
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
'''
Digest認証
'''
auth = HTTPDigestAuth()
users = {
"user": os.environ.get('USER_PW')
}
@auth.get_password
def get_password(username):
if username in users:
return users.get(username)
return False
@auth.error_handler
def auth_error():
response = jsonify({'error': 'unauthorized', 'message': 'Invalid credentials'}
)
response.status_code = 401
return response
'''
View設定
'''
@app.route('/upload')
@auth.login_required
def upload():
return render_template('upload.html')
@app.route('/uploader', methods = ['GET', 'POST'])
def uploader():
if request.method == 'POST':
aws_access_key = os.environ.get('AWS_ACCESS_KEY_ID')
aws_secret_access_key = os.environ.get('AWS_SECRET_ACCESS_KEY')
s3bucket = os.environ.get('S3BUCKET')
f = request.files['file']
s3 = boto.connect_s3(aws_access_key, aws_secret_access_key)
bucket = s3.get_bucket(s3bucket)
key = bucket.new_key(secure_filename(f.filename))
key.set_contents_from_file(f)
return 'file uploaded successfully'
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
webページテンプレート
templates/upload.html
<html>
<body>
<form action = "/uploader" method = "POST" enctype = "multipart/form-data">
<input type = "file" name = "file" />
<input type = "submit"/>
</form>
</body>
</html>
アップロード
例えばiPhoneで上記で構築したhttps://xxxxxxx-xxxxxx-xxxxxx.herokuapp.com/upload
にアクセスすると、下記左のように認証して、右(Choose Fileを押下後)のようなシンプルな画面でファイル選択して、アップロードできる。
ローカルサーバでs3をマウント
上記webページから放り込んだファイルがs3fsでローカルにマウントできる。
sudo s3fs s3バケット名 /home/pi/s3fs_from/ -o allow_other -o uid=1000 -o gid=1000