1
0
Fork 0
mirror of https://github.com/pawelmalak/flame.git synced 2025-07-19 19:49:37 +02:00

Created Cron job to get data from external api every 15 minutes and save it to local database. Created Weather model and controller to get latest weather status

This commit is contained in:
unknown 2021-05-17 18:23:54 +02:00
parent 3fc3d07598
commit adc4aaed0f
8 changed files with 195 additions and 0 deletions

18
controllers/weather.js Normal file
View file

@ -0,0 +1,18 @@
const asyncWrapper = require('../middleware/asyncWrapper');
const ErrorResponse = require('../utils/ErrorResponse');
const Weather = require('../models/Weather');
// @desc Get latest weather status
// @route POST /api/weather
// @access Public
exports.getWeather = asyncWrapper(async (req, res, next) => {
const weather = await Weather.findAll({
order: [['createdAt', 'DESC']],
limit: 1
});
res.status(200).json({
success: true,
data: weather
})
})

15
models/Weather.js Normal file
View file

@ -0,0 +1,15 @@
const { DataTypes } = require('sequelize');
const { sequelize } = require('../db');
const Weather = sequelize.define('Weather', {
externalLastUpdate: DataTypes.STRING,
tempC: DataTypes.FLOAT,
tempF: DataTypes.FLOAT,
isDay: DataTypes.INTEGER,
conditionText: DataTypes.TEXT,
conditionCode: DataTypes.INTEGER
}, {
freezeTableName: true
});
module.exports = Weather;

93
package-lock.json generated
View file

@ -276,6 +276,14 @@
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
"optional": true "optional": true
}, },
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"balanced-match": { "balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -393,6 +401,15 @@
} }
} }
}, },
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"camelcase": { "camelcase": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@ -633,6 +650,15 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
}, },
"cron-parser": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-3.5.0.tgz",
"integrity": "sha512-wyVZtbRs6qDfFd8ap457w3XVntdvqcwBGxBoTvJQH9KGVKL/fB+h2k3C8AqiVxvUQKN1Ps/Ns46CNViOpVDhfQ==",
"requires": {
"is-nan": "^1.3.2",
"luxon": "^1.26.0"
}
},
"crypto-random-string": { "crypto-random-string": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
@ -681,6 +707,14 @@
"integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==",
"dev": true "dev": true
}, },
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"requires": {
"object-keys": "^1.0.12"
}
},
"delayed-stream": { "delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@ -885,6 +919,11 @@
"unpipe": "~1.0.0" "unpipe": "~1.0.0"
} }
}, },
"follow-redirects": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg=="
},
"forever-agent": { "forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@ -1002,6 +1041,16 @@
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
}, },
"get-intrinsic": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
}
},
"get-stream": { "get-stream": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
@ -1104,6 +1153,11 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
}, },
"has-symbols": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
},
"has-unicode": { "has-unicode": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
@ -1273,6 +1327,15 @@
"is-path-inside": "^3.0.1" "is-path-inside": "^3.0.1"
} }
}, },
"is-nan": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
"integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
"requires": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3"
}
},
"is-npm": { "is-npm": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz",
@ -1405,6 +1468,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}, },
"long-timeout": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz",
"integrity": "sha1-lyHXiLR+C8taJMLivuGg2lXatRQ="
},
"lowercase-keys": { "lowercase-keys": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@ -1419,6 +1487,11 @@
"yallist": "^4.0.0" "yallist": "^4.0.0"
} }
}, },
"luxon": {
"version": "1.27.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.27.0.tgz",
"integrity": "sha512-VKsFsPggTA0DvnxtJdiExAucKdAnwbCCNlMM5ENvHlxubqWd0xhZcdb4XgZ7QFNhaRhilXCFxHuoObP5BNA4PA=="
},
"make-dir": { "make-dir": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
@ -1657,6 +1730,16 @@
} }
} }
}, },
"node-schedule": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.0.0.tgz",
"integrity": "sha512-cHc9KEcfiuXxYDU+HjsBVo2FkWL1jRAUoczFoMIzRBpOA4p/NRHuuLs85AWOLgKsHtSPjN8csvwIxc2SqMv+CQ==",
"requires": {
"cron-parser": "^3.1.0",
"long-timeout": "0.1.1",
"sorted-array-functions": "^1.3.0"
}
},
"nodemon": { "nodemon": {
"version": "2.0.7", "version": "2.0.7",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz",
@ -1774,6 +1857,11 @@
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
}, },
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
},
"on-finished": { "on-finished": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@ -2253,6 +2341,11 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
}, },
"sorted-array-functions": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz",
"integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA=="
},
"spawn-command": { "spawn-command": {
"version": "0.0.2-1", "version": "0.0.2-1",
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",

View file

@ -13,10 +13,12 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@types/express": "^4.17.11", "@types/express": "^4.17.11",
"axios": "^0.21.1",
"colors": "^1.4.0", "colors": "^1.4.0",
"concurrently": "^6.0.2", "concurrently": "^6.0.2",
"dotenv": "^9.0.0", "dotenv": "^9.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"node-schedule": "^2.0.0",
"sequelize": "^6.6.2", "sequelize": "^6.6.2",
"sqlite3": "^5.0.2" "sqlite3": "^5.0.2"
}, },

12
routes/weather.js Normal file
View file

@ -0,0 +1,12 @@
const express = require('express');
const router = express.Router();
const {
getWeather
} = require('../controllers/weather');
router
.route('')
.get(getWeather);
module.exports = router;

View file

@ -1,6 +1,7 @@
const express = require('express'); const express = require('express');
const { connectDB } = require('./db'); const { connectDB } = require('./db');
const errorHandler = require('./middleware/errorHandler'); const errorHandler = require('./middleware/errorHandler');
const jobs = require('./utils/jobs');
const colors = require('colors'); const colors = require('colors');
require('dotenv').config(); require('dotenv').config();
@ -19,6 +20,7 @@ app.use(express.json());
// Link controllers with routes // Link controllers with routes
app.use('/api/apps', require('./routes/apps')); app.use('/api/apps', require('./routes/apps'));
app.use('/api/config', require('./routes/config')); app.use('/api/config', require('./routes/config'));
app.use('/api/weather', require('./routes/weather'));
// Custom error handler // Custom error handler
app.use(errorHandler); app.use(errorHandler);

View file

@ -0,0 +1,42 @@
const Config = require('../models/Config');
const Weather = require('../models/Weather');
const axios = require('axios');
const getExternalWeather = async () => {
// Get API key from database
let secret = await Config.findOne({
where: { key: 'WEATHER_API_KEY' }
});
if (!secret) {
console.log('API key was not found');
return;
}
secret = secret.value;
// Fetch data from external API
try {
const res = await axios.get(`http://api.weatherapi.com/v1/current.json?key=${secret}&q=52.229676,21.012229`);
// For dev
// console.log(res.data);
// Save weather data
const cursor = res.data.current;
await Weather.create({
externalLastUpdate: cursor.last_updated,
tempC: cursor.temp_c,
tempF: cursor.temp_f,
isDay: cursor.is_day,
conditionText: cursor.condition.text,
conditionCode: cursor.condition.code
});
} catch (err) {
console.log(err);
console.log('External API request failed');
return;
}
}
module.exports = getExternalWeather;

11
utils/jobs.js Normal file
View file

@ -0,0 +1,11 @@
const schedule = require('node-schedule');
const getExternalWeather = require('./getExternalWeather');
const weatherJob = schedule.scheduleJob('updateWeather', '0 */15 * * * *', async () => {
try {
await getExternalWeather();
console.log('weather updated');
} catch (err) {
console.log(err);
}
})