diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c46fced2..0f837e70f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 1.3.9 (2024-04-xx) ### Common * **core**: `GET /detections` return `Total-items` in response headers +* **core**: Include `timezone` and `country_code` when create site on Arbimon ### Bug Fixes * **core**: Fix update only stream name also set default to timezone and country code diff --git a/core/_services/arbimon/index.js b/core/_services/arbimon/index.js index a2eee87e2..4f20f9885 100644 --- a/core/_services/arbimon/index.js +++ b/core/_services/arbimon/index.js @@ -45,7 +45,7 @@ function updateProject (opts, idToken) { function createSite (stream, idToken) { const body = {}; - ['name', 'latitude', 'longitude', 'altitude', 'hidden'].forEach((attr) => { body[attr] = stream[attr] }) + ['name', 'latitude', 'longitude', 'altitude', 'hidden', 'timezone', 'country_code'].forEach((attr) => { body[attr] = stream[attr] }) body.external_id = stream.id if (!body.altitude) { body.altitude = 0 diff --git a/core/streams/bl/index.js b/core/streams/bl/index.js new file mode 100644 index 000000000..2d180d288 --- /dev/null +++ b/core/streams/bl/index.js @@ -0,0 +1,64 @@ +const arbimonService = require('../../_services/arbimon') +const { randomId } = require('../../../common/crypto/random') +const { ValidationError } = require('../../../common/error-handling/errors') +const dao = require('../dao') + +/** + * Create Stream + * @param {Stream} stream + * @param {string} stream.id + * @param {string} stream.name + * @param {integer} stream.latitude + * @param {integer} stream.longitude + * @param {integer} stream.altitude + * @param {string} stream.description + * @param {boolean} stream.is_public + * @param {integer} stream.external_id + * @param {string} stream.project_id + * @param {boolean} stream.hidden + * @param {*} options + * @param {number} options.creatableBy Create only if site is creatable by the given user id + * @param {string} options.requestSource Whether the request was sent from the Arbimon or not + * @param {string} options.idToken user jwt token + */ +async function create (params, options = {}) { + const stream = { + ...params + } + + if (!params.id) { + stream.id = randomId() + } + + if (params.latitude === 0) { + stream.latitude = null + } + + if (params.longitude === 0) { + stream.longitude = null + } + + if (params.projectId) { + const duplicateStreamInProject = await dao.query({ names: [params.name], projects: [params.projectId] }, { fields: 'id' }) + if (duplicateStreamInProject.total > 0) { + throw new ValidationError('Duplicate stream name in the project') + } + } + // Get timezone and countryCode for Arbimon + const fullStream = { ...stream, ...(await dao.computedAdditions(stream)) } + if (arbimonService.isEnabled && options.requestSource !== 'arbimon') { + try { + const arbimonSite = { ...fullStream, country_code: fullStream.countryCode } + const externalSite = await arbimonService.createSite(arbimonSite, options.idToken) + fullStream.externalId = externalSite.site_id + } catch (error) { + console.error(`Error creating site in Arbimon (stream: ${fullStream.id})`) + throw new Error() + } + } + return await dao.create(fullStream, options) +} + +module.exports = { + create +} diff --git a/core/streams/create.int.test.js b/core/streams/create.int.test.js index d22bf3ecb..827924d54 100644 --- a/core/streams/create.int.test.js +++ b/core/streams/create.int.test.js @@ -48,6 +48,17 @@ describe('POST /streams', () => { latitude: 10.123, longitude: 101.456 } + const mockCountry = jest.spyOn(googleMap, 'getCountry') + mockCountry.mockReturnValueOnce({ + data: { + results: [] + } + }) + const mockTimezone = jest.spyOn(googleMap, 'getTimezone') + mockTimezone.mockReturnValueOnce({ + data: {} + }) + const response = await request(app).post('/').send(requestBody) expect(response.statusCode).toBe(500) diff --git a/core/streams/create.js b/core/streams/create.js index 2b3bb602e..b0f3b1713 100644 --- a/core/streams/create.js +++ b/core/streams/create.js @@ -1,9 +1,6 @@ const { httpErrorHandler } = require('../../common/error-handling/http') -const dao = require('./dao') -const { randomId } = require('../../common/crypto/random') const Converter = require('../../common/converter') -const arbimonService = require('../_services/arbimon') -const { ValidationError } = require('../../common/error-handling/errors') +const { create } = require('./bl') /** * @swagger @@ -36,6 +33,10 @@ const { ValidationError } = require('../../common/error-handling/errors') */ module.exports = (req, res) => { const user = req.rfcx.auth_token_info + const creatableBy = user.is_super || user.has_system_role ? undefined : user.id + const requestSource = req.headers.source + const idToken = req.headers.authorization + const options = { creatableBy, requestSource, idToken } const converter = new Converter(req.body, {}, true) converter.convert('id').optional().toString().minLength(12).maxLength(12).isPassingRegExp(/[a-z0-9]{12}/, 'should have only lowercase characters and integers') converter.convert('name').toString() @@ -50,46 +51,9 @@ module.exports = (req, res) => { return converter.validate() .then(async (params) => { - const stream = { - ...params, - createdById: user.id - } - if (!params.id) { - stream.id = randomId() - } - - if (params.latitude === 0) { - stream.latitude = null - } - - if (params.longitude === 0) { - stream.longitude = null - } - - if (params.projectId) { - const duplicateStreamInProject = await dao.query({ names: [params.name], projects: [params.projectId] }, { fields: 'id' }) - if (duplicateStreamInProject.total > 0) { - throw new ValidationError('Duplicate stream name in the project') - } - } - - // TODO move - route handler should not contain business logic - if (arbimonService.isEnabled && req.headers.source !== 'arbimon') { - try { - const externalSite = await arbimonService.createSite(stream, req.headers.authorization) - stream.externalId = externalSite.site_id - } catch (error) { - console.error(`Error creating site in Arbimon (stream: ${stream.id})`) - throw new Error() - } - } - - const options = { - creatableBy: (user.is_super || user.has_system_role) ? undefined : user.id - } - const createdStream = await dao.create(stream, options) - - return res.location(`/streams/${createdStream.id}`).sendStatus(201) + params.createdById = user.id + return await create(params, options) }) + .then(stream => res.location(`/streams/${stream.id}`).sendStatus(201)) .catch(httpErrorHandler(req, res, 'Failed creating stream')) } diff --git a/core/streams/dao/index.js b/core/streams/dao/index.js index a171e42a6..217f3a6e1 100644 --- a/core/streams/dao/index.js +++ b/core/streams/dao/index.js @@ -76,7 +76,12 @@ async function get (idOrWhere, options = {}) { * @param {*} options */ async function create (stream, options = {}) { - const fullStream = { ...stream, ...(await computedAdditions(stream)) } + let additionals = {} + // If timezone and countryCode already existing in stream blob then no need to get them again + if (!stream.timezone && !stream.countryCode) { + additionals = await computedAdditions(stream) + } + const fullStream = { ...stream, ...additionals } if (fullStream.projectId && options.creatableBy && !(await hasPermission(UPDATE, options.creatableBy, fullStream.projectId, PROJECT))) { throw new ForbiddenError() }