Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: now() function timezone offset #3040

Merged
merged 13 commits into from
Oct 4, 2023
Merged
11 changes: 10 additions & 1 deletion core/dateUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@ import {

import { isBlank } from './stringUtils'

export { parseISO, subDays, addDays, differenceInDays, differenceInHours, subMonths, subYears } from 'date-fns'
export {
parseISO,
subDays,
addDays,
addMinutes,
differenceInDays,
differenceInHours,
subMonths,
subYears,
} from 'date-fns'

export const formats = {
dateDefault: 'dd/MM/yyyy',
Expand Down
16 changes: 12 additions & 4 deletions core/record/_record/recordNodesUpdater.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ const _getOrCreateEntityByKeys =
return { entity: entityInserted, updateResult }
}

const _afterNodesUpdate = async ({ survey, record, nodes, sideEffect = false }) => {
const _afterNodesUpdate = async ({ survey, record, nodes, timezoneOffset, sideEffect = false }) => {
// output
const updateResult = new RecordUpdateResult({ record, nodes })

Expand All @@ -218,6 +218,7 @@ const _afterNodesUpdate = async ({ survey, record, nodes, sideEffect = false })
survey,
record,
nodes,
timezoneOffset,
sideEffect,
})

Expand All @@ -240,7 +241,7 @@ const _afterNodesUpdate = async ({ survey, record, nodes, sideEffect = false })
}

const updateAttributesWithValues =
({ survey, entityDefUuid, valuesByDefUuid, insertMissingNodes = false, sideEffect = false }) =>
({ survey, entityDefUuid, valuesByDefUuid, timezoneOffset, insertMissingNodes = false, sideEffect = false }) =>
async (record) => {
const updateResult = new RecordUpdateResult({ record })

Expand All @@ -253,6 +254,7 @@ const updateAttributesWithValues =
survey,
record: nodeUpdateResult.record,
nodes: nodeUpdateResult.nodes,
timezoneOffset,
sideEffect,
})
updateResult.merge(dependentsUpdateResult)
Expand Down Expand Up @@ -399,7 +401,7 @@ const _mergeEntities = ({ survey, recordSource, recordTarget, entitySource, enti
}

const replaceUpdatedNodes =
({ survey, recordSource, sideEffect = false }) =>
({ survey, recordSource, timezoneOffset, sideEffect = false }) =>
async (recordTarget) => {
const rootSource = RecordReader.getRootNode(recordSource)
const rootTarget = RecordReader.getRootNode(recordTarget)
Expand All @@ -415,7 +417,13 @@ const replaceUpdatedNodes =
entityTarget: rootTarget,
sideEffect,
})
return _afterNodesUpdate({ survey, record: updateResult.record, nodes: updateResult.nodes, sideEffect })
return _afterNodesUpdate({
survey,
record: updateResult.record,
nodes: updateResult.nodes,
timezoneOffset,
sideEffect,
})
}

export const RecordNodesUpdater = {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"@mui/material": "^5.14.10",
"@mui/x-data-grid": "^6.14.0",
"@mui/x-date-pickers": "^6.14.0",
"@openforis/arena-core": "^0.0.166",
"@openforis/arena-core": "^0.0.169",
"@openforis/arena-server": "^0.1.29",
"@sendgrid/mail": "^7.7.0",
"@shopify/draggable": "^1.0.0-beta.8",
Expand Down
12 changes: 6 additions & 6 deletions server/modules/record/api/recordApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ export const init = (app) => {
app.post('/survey/:surveyId/record/:recordUuid/node', requireRecordEditPermission, async (req, res, next) => {
try {
const user = Request.getUser(req)
const { surveyId, cycle, draft } = Request.getParams(req)
const { surveyId, cycle, draft, timezoneOffset } = Request.getParams(req)
const node = Request.getJsonParam(req, 'node')
const file = Request.getFile(req)
const socketId = Request.getSocketId(req)

await RecordService.persistNode({ socketId, user, surveyId, cycle, draft, node, file })
await RecordService.persistNode({ socketId, user, surveyId, cycle, draft, node, file, timezoneOffset })

sendOk(res)
} catch (error) {
Expand Down Expand Up @@ -328,11 +328,11 @@ export const init = (app) => {
// RECORD Check in / out
app.post('/survey/:surveyId/record/:recordUuid/checkin', requireRecordViewPermission, async (req, res, next) => {
try {
const { surveyId, recordUuid, draft } = Request.getParams(req)
const { surveyId, recordUuid, draft, timezoneOffset } = Request.getParams(req)
const user = Request.getUser(req)
const socketId = Request.getSocketId(req)

const record = await RecordService.checkIn({ socketId, user, surveyId, recordUuid, draft })
const record = await RecordService.checkIn({ socketId, user, surveyId, recordUuid, draft, timezoneOffset })

res.json({ record })
} catch (error) {
Expand Down Expand Up @@ -397,11 +397,11 @@ export const init = (app) => {
})

app.delete('/survey/:surveyId/record/:recordUuid/node/:nodeUuid', requireRecordEditPermission, (req, res) => {
const { surveyId, cycle, draft, recordUuid, nodeUuid } = Request.getParams(req)
const { surveyId, cycle, draft, recordUuid, nodeUuid, timezoneOffset } = Request.getParams(req)
const user = Request.getUser(req)
const socketId = Request.getSocketId(req)

RecordService.deleteNode({ socketId, user, surveyId, cycle, draft, recordUuid, nodeUuid })
RecordService.deleteNode({ socketId, user, surveyId, cycle, draft, recordUuid, nodeUuid, timezoneOffset })
sendOk(res)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const insertNodesInBatch = async ({ user, surveyId, nodes, systemActivity
}

export const insertNode = async (
{ user, survey, record, node, system, persistNodes = true, createMultipleEntities = true },
{ user, survey, record, node, system, timezoneOffset, persistNodes = true, createMultipleEntities = true },
t
) => {
const surveyId = Survey.getId(survey)
Expand All @@ -85,6 +85,7 @@ export const insertNode = async (
record,
parentNode: node,
nodeDef,
timezoneOffset,
createMultipleEntities,
})
Object.assign(nodesCreated, descendantsCreateResult.nodes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,15 @@ const _reloadNodes = async ({ surveyId, record, nodes }, tx) => {
return ObjectUtils.toUuidIndexedObj(nodesReloadedArray)
}

export const updateNodesDependents = async ({ survey, record, nodes, persistNodes = true, sideEffect = false }, tx) => {
export const updateNodesDependents = async (
{ survey, record, nodes, timezoneOffset, persistNodes = true, sideEffect = false },
tx
) => {
const { record: recordUpdatedDependents, nodes: nodesUpdated } = Record.updateNodesDependents({
survey,
record,
nodes,
timezoneOffset,
logger,
sideEffect,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ import { NodeRdbManager } from './nodeRDBManager'
// ==== CREATE

export const initNewRecord = async (
{ user, survey, record, nodesUpdateListener = null, nodesValidationListener = null, createMultipleEntities = true },
{
user,
survey,
record,
timezoneOffset,
nodesUpdateListener = null,
nodesValidationListener = null,
createMultipleEntities = true,
},
client = db
) => {
const rootNodeDef = Survey.getNodeDefRoot(survey)
Expand All @@ -51,6 +59,7 @@ export const initNewRecord = async (
survey,
record,
node: rootNode,
timezoneOffset,
nodesUpdateListener,
nodesValidationListener,
system: true,
Expand Down Expand Up @@ -170,6 +179,7 @@ export const persistNode = async (
survey,
record,
node,
timezoneOffset,
nodesUpdateListener = null,
nodesValidationListener = null,
system = false,
Expand All @@ -182,6 +192,7 @@ export const persistNode = async (
survey,
record,
node,
timezoneOffset,
async (user, survey, record, node, t) => {
const nodeUuid = Node.getUuid(node)

Expand All @@ -190,7 +201,10 @@ export const persistNode = async (
if (existingNode) {
return NodeUpdateManager.updateNode({ user, survey, record, node, system }, t)
}
return NodeCreationManager.insertNode({ user, survey, record, node, system, createMultipleEntities }, t)
return NodeCreationManager.insertNode(
{ user, survey, record, node, system, createMultipleEntities, timezoneOffset },
t
)
},
nodesUpdateListener,
nodesValidationListener,
Expand Down Expand Up @@ -226,6 +240,7 @@ const _updateNodeAndValidateRecordUniqueness = async (
survey,
record,
node,
timezoneOffset,
nodesUpdateFn,
nodesUpdateListener = null,
nodesValidationListener = null,
Expand All @@ -238,7 +253,7 @@ const _updateNodeAndValidateRecordUniqueness = async (
let recordUpdated = recordUpdated1

const { record: recordUpdated2, nodes: updatedNodesAndDependents } = await _onNodesUpdate(
{ survey, record: recordUpdated, nodesUpdated, nodesUpdateListener, nodesValidationListener },
{ survey, record: recordUpdated, nodesUpdated, timezoneOffset, nodesUpdateListener, nodesValidationListener },
t
)
recordUpdated = recordUpdated2
Expand Down Expand Up @@ -291,15 +306,18 @@ const _getDependentNodesToValidate = ({ survey, record, nodes }) => {
return { ...nodes, ...ObjectUtils.toUuidIndexedObj(dependentNodesToValidate) }
}

const _onNodesUpdate = async ({ survey, record, nodesUpdated, nodesUpdateListener, nodesValidationListener }, t) => {
const _onNodesUpdate = async (
{ survey, record, nodesUpdated, timezoneOffset, nodesUpdateListener, nodesValidationListener },
t
) => {
// 1. update record and notify
if (nodesUpdateListener) {
nodesUpdateListener(nodesUpdated)
}

// 2. update dependent nodes
const { record: recordUpdatedDependentNodes, nodes: updatedDependentNodes } =
await NodeUpdateManager.updateNodesDependents({ survey, record, nodes: nodesUpdated }, t)
await NodeUpdateManager.updateNodesDependents({ survey, record, nodes: nodesUpdated, timezoneOffset }, t)
if (nodesUpdateListener) {
nodesUpdateListener(updatedDependentNodes)
}
Expand Down
25 changes: 21 additions & 4 deletions server/modules/record/service/recordService.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export const deleteRecordsPreview = async (olderThan24Hours = false) => {
return count
}

export const checkIn = async ({ socketId, user, surveyId, recordUuid, draft }) => {
export const checkIn = async ({ socketId, user, surveyId, recordUuid, draft, timezoneOffset }) => {
const survey = await SurveyManager.fetchSurveyById({ surveyId, draft })
const surveyInfo = Survey.getSurveyInfo(survey)
const record = await RecordManager.fetchRecordAndNodesByUuid({ surveyId, recordUuid, draft })
Expand All @@ -163,7 +163,13 @@ export const checkIn = async ({ socketId, user, surveyId, recordUuid, draft }) =
const thread = RecordsUpdateThreadService.getOrCreatedThread({ surveyId, cycle, draft: preview })
// initialize record if empty
if (Record.getNodesArray(record).length === 0) {
thread.postMessage({ type: RecordsUpdateThreadMessageTypes.recordInit, user, surveyId, recordUuid })
thread.postMessage({
type: RecordsUpdateThreadMessageTypes.recordInit,
user,
surveyId,
recordUuid,
timezoneOffset,
})
}
}
return record
Expand Down Expand Up @@ -304,7 +310,16 @@ const _sendNodeUpdateMessage = ({ socketId, user, surveyId, cycle, recordUuid, d

export const { fetchNodeByUuid } = RecordManager

export const persistNode = async ({ socketId, user, surveyId, draft, cycle, node, file = null }) => {
export const persistNode = async ({
socketId,
user,
surveyId,
draft,
cycle,
node,
file = null,
timezoneOffset = null,
}) => {
const recordUuid = Node.getRecordUuid(node)

if (file) {
Expand All @@ -331,11 +346,12 @@ export const persistNode = async ({ socketId, user, surveyId, draft, cycle, node
type: RecordsUpdateThreadMessageTypes.nodePersist,
node,
user,
timezoneOffset,
},
})
}

export const deleteNode = ({ socketId, user, surveyId, cycle, draft, recordUuid, nodeUuid }) =>
export const deleteNode = ({ socketId, user, surveyId, cycle, draft, recordUuid, nodeUuid, timezoneOffset }) =>
_sendNodeUpdateMessage({
socketId,
user,
Expand All @@ -348,6 +364,7 @@ export const deleteNode = ({ socketId, user, surveyId, cycle, draft, recordUuid,
recordUuid,
nodeUuid,
user,
timezoneOffset,
},
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,15 @@ class RecordsUpdateThread extends Thread {

async processRecordInitMsg(msg) {
const { survey, surveyId } = this
const { recordUuid, user } = msg
const { recordUuid, user, timezoneOffset } = msg

let record = await RecordManager.fetchRecordAndNodesByUuid({ surveyId, recordUuid })

record = await RecordManager.initNewRecord({
user,
survey,
record,
timezoneOffset,
nodesUpdateListener: (updatedNodes) => this.handleNodesUpdated.bind(this)({ record, updatedNodes }),
nodesValidationListener: (validations) => this.handleNodesValidationUpdated.bind(this)({ record, validations }),
})
Expand All @@ -173,14 +174,15 @@ class RecordsUpdateThread extends Thread {

async processRecordNodePersistMsg(msg) {
const { survey } = this
const { node, user } = msg
const { node, user, timezoneOffset } = msg
const recordUuid = Node.getRecordUuid(node)
let record = await this.getOrFetchRecord({ recordUuid })
record = await RecordManager.persistNode({
user,
survey,
record,
node,
timezoneOffset,
nodesUpdateListener: (updatedNodes) => this.handleNodesUpdated({ record, updatedNodes }),
nodesValidationListener: (validations) => this.handleNodesValidationUpdated({ record, validations }),
})
Expand Down
13 changes: 10 additions & 3 deletions test/e2e/tests/surveyFormPreview.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as DateUtils from '../../../core/dateUtils'
import { TestId, getSelector } from '../../../webapp/utils/testId'
import { cluster, plot, tree } from '../mock/nodeDefs'
import { gotoFormPage } from './_formDesigner'
Expand Down Expand Up @@ -57,9 +58,15 @@ export default () =>
verifyAttribute(cluster_coordinate, { x: '', y: '', srs: '4326', srsLabel: 'WGS 1984 (EPSG:4326)' })
verifyAttribute(cluster_time, () => {
// it is possible the default value was set one minute after the startTime was initialized in the test
const date = new Date(startTime)
date.setMinutes(date.getMinutes() + 1)
return `(${formatTime(startTime)})|(${formatTime(date)})`
const startTimeDate = new Date(startTime)
const startTimePlus1Minute = DateUtils.addMinutes(startTimeDate, 1)
const possibleDateValues = [new Date(startTime), startTimePlus1Minute]
const expectedPossibleValues = possibleDateValues.map((possibleDateValue) => {
const timezoneOffsetDiff = startTimeDate.getTimezoneOffset() - -120 // browser timezone=Europe/Rome
const dateWithTimezoneOffset = DateUtils.addMinutes(possibleDateValue, timezoneOffsetDiff)
return formatTime(dateWithTimezoneOffset)
})
return `(${expectedPossibleValues.join('|')})`
})
verifyAttribute(cluster_date, () => startTime)

Expand Down
4 changes: 4 additions & 0 deletions webapp/components/form/DateTimeInput/DateInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
width: 7rem;
padding: 4px 6px;
}

.MuiIconButton-root {
padding: 0;
}
}
Loading