- やりたいこと
- 参考
- 検証環境
- Data Bucket に未認証ユーザーが書き込めるような環境を AWS CLI で用意する
- あとは HTML と JavaScript でフォームを用意して HTML Bucket に放り込む
- 集計とか
- 以上
やりたいこと
- S3 で構成されたサイトに HTML フォームを実装し、アンケートページ的なものを提供したい
- 最終的には S3 の前には CloudFront を挟む予定
- 投稿の内容は S3 に JSON で保存する
図にすると以下のような感じ。
参考
ありがとうございます。ほぼ、上記ページの写経となります。
HTML フォームを JavaScript から扱う方法は上記のページが参考になりました。有難うございます。
検証環境
OS
$ sw_vers ProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G1217
AWS CLI
$ aws --version
aws-cli/1.11.19 Python/2.7.10 Darwin/15.6.0 botocore/1.4.76
Data Bucket に未認証ユーザーが書き込めるような環境を AWS CLI で用意する
Cognito や IAM 等を色々と設定する必要があるけど、AWS CLI で全部準備する。
# # 各環境変数に値を定義 # _PROFILE=washino-profile _REGION=ap-northeast-1 _DOMAIN_NAME=washi.inokara.tech _IDENTITY_POOL_NAME=washino_identity _S3_BUCKET_NAME=data-bucket # # identity pool を作成 # _IDENTITY_POOL_ID=$(aws --profile ${_PROFILE} cognito-identity create-identity-pool --identity-pool-name ${_IDENTITY_POOL_NAME} --allow-unauthenticated-identities --query IdentityPoolId --output text) echo ${_IDENTITY_POOL_ID} # # S3 バケットを作成 # aws --profile ${_PROFILE} --region ${_REGION} s3 mb s3://${_S3_BUCKET_NAME} # # 作成したバケットに CORS を設定(これをやっとかんといかんばい) # cat << EOT >> cors.json { "CORSRules": [ { "AllowedOrigins": ["https://${_DOMAIN_NAME}"], "AllowedHeaders": ["*"], "AllowedMethods": ["PUT"] } ] } EOT aws --profile ${_PROFILE} s3api put-bucket-cors --bucket ${_S3_BUCKET_NAME} --cors-configuration file://cors.json # # バケットポリシーを作成 # cat << EOT >> s3PutAllowPolicy.json { "Version": "2012-10-17", "Statement": [ { "Sid": "S3PutAllowPolicy", "Effect": "Allow", "Action": [ "s3:PutObject", "s3:PutObjectAcl" ], "Resource": "arn:aws:s3:::${_S3_BUCKET_NAME}/*" } ] } EOT _POLICY_ARN=$(aws --profile ${_PROFILE} iam create-policy --policy-name s3PutAllowPolicy --policy-document file://s3PutAllowPolicy.json --query Policy.Arn --output text) echo ${_POLICY_ARN} # # identity pool に付与する IAM Role を作成 # cat << EOT >> ${_IDENTITY_POOL_NAME}_authenticated.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": "${_IDENTITY_POOL_ID}" }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" } } } ] } EOT _IAM_ROLE_ARN=$(aws --profile ${_PROFILE} iam create-role --role-name cognito_${_IDENTITY_POOL_NAME}_authenticated --assume-role-policy-document file://${_IDENTITY_POOL_NAME}_authenticated.json --query Role.Arn --output text) aws --profile ${_PROFILE} iam attach-role-policy --role-name cognito_${_IDENTITY_POOL_NAME}_authenticated --policy-arn ${_POLICY_ARN} # # identity pool に IAM Role を適用する # aws --profile ${_PROFILE} cognito-identity set-identity-pool-roles --identity-pool-id ${_IDENTITY_POOL_ID} --roles authenticated=${_IAM_ROLE_ARN} # # identity pool に付与する IAM Role を作成(未認証ユーザー用) # cat << EOT >> ${_IDENTITY_POOL_NAME}_unauthenticated.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": "${_IDENTITY_POOL_ID}" }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "unauthenticated" } } } ] } EOT _IAM_ROLE_ARN=$(aws --profile ${_PROFILE} iam create-role --role-name cognito_${_IDENTITY_POOL_NAME}_unauthenticated --assume-role-policy-document file://${_IDENTITY_POOL_NAME}_unauthenticated.json --query Role.Arn --output text) aws --profile ${_PROFILE} iam attach-role-policy --role-name cognito_${_IDENTITY_POOL_NAME}_unauthenticated --policy-arn ${_POLICY_ARN} # # identity pool に IAM Role を適用する # aws --profile ${_PROFILE} cognito-identity set-identity-pool-roles --identity-pool-id ${_IDENTITY_POOL_ID} --roles unauthenticated=${_IAM_ROLE_ARN} # # 後片付け(やらなくても良い) # rm -f cors.json s3PutAllowPolicy.json ${_IDENTITY_POOL_NAME}_authenticated.json ${_IDENTITY_POOL_NAME}_unauthenticated.json
あとは HTML と JavaScript でフォームを用意して HTML Bucket に放り込む
HTML はこんな感じ
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script src="aws-sdk.min.js"></script> <script src="demo.js"></script> <title>雑なアンケート</title> </head> <body> <form name='orenoForm'> <table> <tr> <th>お名前</th> <td> <input name="_name" type="text" maxlength="50" value="" /> </td> </tr> <tr> <th>メールアドレス</th> <td> <input name="_mail" type="email" maxlength="50" value="" /> </td> </tr> <tr> <th>性別</th> <td> <input name="_sex" type="radio" value="男"/>男</input> <input name="_sex" type="radio" value="女"/>女</input> <input name="_sex" type="radio" value="未選択" checked="checked" />未選択</input> </td> </tr> <tr> <th>世の中に不満を</th> <td> <input name="_fuman" type="radio" value="感じる"/>感じる</input> <input name="_fuman" type="radio" value="感じない"/>感じない</input> <input name="_fuman" type="radio" value="未選択" checked="checked" />未選択</input> </td> </tr> <tr> <th>2017 年ホークスは</th> <td> <input name="_hawks" type="radio" value="優勝する"/>優勝する</input> <input name="_hawks" type="radio" value="優勝しない"/>優勝しない</input> <input name="_hawks" type="radio" value="未選択" checked="checked" />未選択</input> </td> </tr> <tr> <th>コメントをどうぞ</th> <td> <TEXTAREA name="_comment" cols="40" rows="6" name="comment"></TEXTAREA> </td> </tr> </table> <input onClick="postMessage();" type="button" value="投稿"/> </form> </body> </html>
JavaScript はこんな感じ
// // demo.js // var $aws_region = "ap-northeast-1"; var $aws_cognito_identity_pool_id = "ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx"; // Cognito で作成した identity pool id を設定する var $s3_prefix = "data/201702/"; var $s3_bucket = "xxxxxxxxxxxxxxxxxxxxxxxx"; AWS.config.region = $aws_region; AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: $aws_cognito_identity_pool_id}); // AWS.config.credentials.get(function(err) { // if (!err) { // console.log("Cognito Identify Id: " + AWS.config.credentials.identityId); // } // }); function postMessage() { var form = document.forms.orenoForm; var now = new Date(); var obj = {"name": form._name.value, "mail": form._mail.value, "comment": form._comment.value, "sex": form._sex.value, "fuman": form._fuman.value, "hawks": form._hawks.value, "date": now.toLocaleString()}; var s3 = new AWS.S3({params: {Bucket: $s3_bucket}}); var blob = new Blob([JSON.stringify(obj, null, 2)], {type:'text/plain'}); s3.putObject({Key: $s3_prefix + now.getTime() +".json", ContentType: "text/plain", Body: blob, ACL: "public-read"}, function(err, data){ if(data !== null){ location.href="thanks.html"; } else{ alert("Post Failed: " + err.message); } }); }
Chrome で見ると…
なんかアンケートページっぽいですな。
アンケートに答えると…
以下のように S3 バケットに JSON データが保存される。
bash-3.2$ ls -tr *.json 1486298468151.json 1486298522074.json 1486298702117.json bash-3.2$ cat 1486298702117.json | jq . { "date": "2017/2/5 21:45:02", "hawks": "優勝する", "fuman": "感じない", "sex": "女", "comment": "ああああ", "mail": "hanako@example.com", "name": "やまだはなこ" }
集計とか
S3 の put イベントを拾って Lambda と組み合わせる例が紹介されているけど、とりあえずは Google SpreadSheet に結果を突っ込んでおけば良さそうということで、以下の記事のように Google SpreadSheet に突っ込んでおくことにする。
Elasticsearch とかに突っ込んでも面白そうだけど。
以上
メモでした。