Node.jsで退勤時間の自動打刻システムを作る

## はじめに
私の勤めている会社は退勤時にweb上で打刻、もしくは後で退勤時間を記載するという仕組みになっています。
その打刻するサイトのUIがあまりも使いにくく、さらに23時頃に退勤の日とかいちいちwebを開いて打刻するのが超めんどくさいのです。
そこで会社から離れたら自動的に打刻するシステムを作ろうと思ったのでレシピを下記に記述します。

## 前提条件
Node.jsがローカルPCに入っていること
npm or yarnがローカルPCに入っていること
会社の無線LANに接続できること(有線と同時接続でもOK)
[googleApi](https://console.developers.google.com/apis/library)に登録していること(無料。クレジットカード登録とかもいらない)

## 仕組み
PCのMACアドレスから現在地を特定して会社にいる場合は時間を記録し続けるという仕組み

## 作り方
googleApiは下記2つを使用する
[Google Maps Geolocation API](https://developers.google.com/maps/documentation/geolocation/intro?hl=ja)
[Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/intro?hl=ja)

[googleApi](https://console.developers.google.com/apis/library)に登録していてAPIキーを取得していれば２つともそのキーで下のソースのAPIを叩けるため特に意識することはないです。

``` sh:command
mkdir worktimelog
cd worktimelog
mkdir timecard
mkdir logs
npm init
```

npm initの内容は適当でいいです。(一応サンプル載せます)

``` sh:command
package name: worktimelog
version: (1.0.0) 1.0.0
description: worktimelog
entry point: (index.js) cron.js
test command: node cron.js
git repository:(エンターキー押してスキップしてください)
keywords: worktimelog
author: taisei_otsuka
```

npm init完了しましたら

``` sh:command
npm install date-utils
npm install fs
npm install request
npm install wifi_location
vim cron.js
```

cron.jsの中身です。

``` js:cron.js
#!/usr/bin/env node
require("date-utils");
const fs = require("fs");
const request = require('request');
const wifiLocation = require("wifi_location");
// googleApiのapiキー
const apikey = "apikey";
const date = new Date();
// logsまでの絶対パス
const logFile = "logsまでの絶対パス" + date.toFormat("YYYYMMDD") + "_log.txt";
// timecardまでの絶対パス
const timecardFile = "timecardまでの絶対パス" + date.toFormat("YYYYMMDD") + "_timecard.txt";
// 会社の郵便番号
const address = "000-0000";
const dateFormat = date.toFormat("YYYY-MM-DD HH24:MI");
const timeAndMemory = "time -> " + dateFormat + " memory -> " + process.memoryUsage().rss;
function writeLog(log) {
	fs.appendFile(logFile, "\n" + log, function (err) {
		if (err) {
			throw err;
		}
	});
}
fs.access(timecardFile, fs.constants.R_OK | fs.constants.W_OK, (err) => {
	if (err) fs.writeFile(timecardFile, date.toFormat("YYYY-MM-DD HH24:MI"));
});
fs.access(logFile, fs.constants.R_OK | fs.constants.W_OK, (err) => {
	if (err) fs.writeFile(logFile, date.toFormat("ログを開始します。" + timeAndMemory));
});
wifiLocation.wifiTowers(function(err, obj) {
	if (obj.length === 0) writeLog("MACアドレスを取得できませんでした。" + dateFormat);
	let array = [];
	obj.map((value) => {
		delete value.ssid;
		return array.push({macAddress:value.mac_address,signalStrength:value.signal_strength});
	});
	let optionsPost = {
		url: "https://www.googleapis.com/geolocation/v1/geolocate?key=" + apikey,
		method: "POST",
		body: '{"considerIp": "false","wifiAccessPoints": ' + JSON.stringify(array) + '}',
		headers: {
			"Content-Type": "application/json"
		},
	};
	request(optionsPost, (error, response, body) => {
		if (!error && response.statusCode == 200) {
			body = JSON.parse(body).location;
			latlng = body.lat + "," + body.lng;
			let optionsGet = {
				url: "https://maps.googleapis.com/maps/api/geocode/json",
				qs: {
					latlng: latlng,
					key: apikey
				}
			};
			request(optionsGet, (error, response, body) => {
				if (!error && response.statusCode === 200) {
					let addressBool = false;
					JSON.parse(body).results[0].address_components.map((value) => {
						if (value.types[0] === "postal_code") addressBool = value.long_name === address;
					});
					if (addressBool) {
						fs.writeFile(timecardFile, dateFormat);
						writeLog("書き込みました。" + timeAndMemory);
					}
				}
			});
		}
	});
});

```

はい、お気づきかと思いますがローカルpcでcronする必要があります。

``` sh:command
*/15 0,18-23 * * 1-5  /usr/local/bin/node /hogehoge/worktimelog/cron.js /dev/null 2>&1
```

月~金の18時~0時までの間15分おきにcron.jsを実行しますという意味です。

cronの設定方法がわからない方は、foreverを使用しcronの処理をデーモン化してみてください。

``` sh:command
npm install cron time
npm install forever -g
```

foreverとnpm cronの併用の場合の記述方法

``` js:cron.js
const {CronJob} = require("cron");
new CronJob("*/15 0,18-23 * * 1-5", () => {
// ここに上記のcr....
```

[続きはこちらへ移転しました!](https://se-taisei.com/items/js/work-time)