Skip to content

Instantly share code, notes, and snippets.

@tmokmss
Last active May 12, 2022 00:42
Show Gist options
  • Save tmokmss/3dd85889415806d13306882b2fb69785 to your computer and use it in GitHub Desktop.
Save tmokmss/3dd85889415806d13306882b2fb69785 to your computer and use it in GitHub Desktop.
Survey form powered by Lambda function URL
const https = require('https')
exports.handler = async (event) => {
console.log(event)
const req = event.requestContext.http;
const sourceIp = req.sourceIp;
// can perform IP address restriction here
// e.g. if (sourceIp != "11.4.51.4") throw new Error()
if (req.method == 'GET') {
if (!(req.path == '/')) {
return {
statusCode: 404,
body: 'Not found',
};
}
return {
statusCode: 200,
body: getHTML(),
headers: {
'content-type': 'text/html'
}
};
}
else if (req.method == 'POST') {
const response = JSON.parse(event.body);
await processResponse(response);
return {
statusCode: 200,
body: 'success',
};
}
return {
statusCode: 400,
body: 'Bad Request',
}
};
const processResponse = async (response) => {
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
await post(webhookUrl, response);
};
const post = async (url, data) => {
// c.f. https://stackoverflow.com/questions/40537749/how-do-i-make-a-https-post-in-node-js-without-any-third-party-module
const dataString = JSON.stringify(data)
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
timeout: 3000, // in ms
}
return new Promise((resolve, reject) => {
const req = https.request(url, options, (res) => {
if (res.statusCode < 200 || res.statusCode > 299) {
return reject(new Error(`HTTP status code ${res.statusCode}`))
}
const body = []
res.on('data', (chunk) => body.push(chunk))
res.on('end', () => {
const resString = Buffer.concat(body).toString()
resolve(resString)
})
})
req.on('error', (err) => {
reject(err)
})
req.on('timeout', () => {
req.destroy()
reject(new Error('Request time out'))
})
req.write(dataString)
req.end()
})
}
const getHTML = () => {
return `
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div class="flex container mx-auto py-10">
<div class="grow">
<form id="myForm">
<div class="mb-6">
<label for="q1" class="block mb-2 text-sm font-medium text-gray-900">Q1. 名前を教えて下さい。</label>
<input
type="text"
id="q1"
name="q1"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
placeholder="それゆけコテッチャン"
required
/>
</div>
<div class="mb-6">
<label for="q2" class="block mb-2 text-sm font-medium text-gray-900">Q2. 性別を教えて下さい。</label>
<div class="flex items-center mb-4">
<input
id="q2-1"
type="radio"
value="male"
name="q2"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500focus:ring-2"
/>
<label for="default-radio-1" class="ml-2 text-sm font-medium text-gray-900">男子</label>
</div>
<div class="flex items-center mb-4">
<input
checked
id="q2-2"
type="radio"
value="female"
name="q2"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 focus:ring-2"
/>
<label for="default-radio-2" class="ml-2 text-sm font-medium text-gray-900">女子</label>
</div>
<div class="flex items-center">
<input
checked
id="q2-3"
type="radio"
value="other"
name="q2"
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 focus:ring-2"
/>
<label for="default-radio-2" class="ml-2 text-sm font-medium text-gray-900">そうでない人</label>
</div>
</div>
<div class="mb-6">
<label for="q3" class="block mb-2 text-sm font-medium text-gray-900"
>Q3. 好きなモツを1つ教えて下さい。</label
>
<input
type="text"
id="q3"
name="q3"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
placeholder="コブクロ"
required
/>
</div>
<div class="mb-6">
<label for="message" class="block mb-2 text-sm font-medium text-gray-900"
>Q4. Q3でそう答えた理由を教えて下さい。</label
>
<textarea
id="message"
name="q4"
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
placeholder="Type here..."
></textarea>
</div>
<div class="mb-6">
<label for="message" class="block mb-2 text-sm font-medium text-gray-900"
>Q5. 最後に感想があれば教えて下さい。</label
>
<textarea
id="message"
name="q5"
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
placeholder="Type here..."
></textarea>
</div>
<div>
<button
type="submit"
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
>
Submit
</button>
<label id="statusLabel" class="text-sm text-gray-900" style="display: none"></label>
</div>
</form>
</div>
</div>
<script>
$('#myForm').submit(function (event) {
event.preventDefault();
var $form = $(this);
var $button = $form.find('button');
var $status = $('#statusLabel');
$.ajax({
url: '/',
type: 'POST',
data: JSON.stringify(
$form.serializeArray().reduce((json, { name, value }) => {
json[name] = value;
return json;
}, {}),
),
headers: {
'Content-Type': 'application/json',
},
beforeSend: (_, settings) => {
$button.attr('disabled', true);
},
complete: (_, textStatus) => {
console.log(textStatus);
if (textStatus == 'error') {
$status.text('送信に失敗しました… もう一度お試しください');
$status.show();
$button.attr('disabled', false);
} else {
$status.text('回答を送信しました!');
$status.show();
$button.hide();
}
},
});
});
</script>
</body>
</html>
`;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment