@@ -23,14 +23,14 @@ export function SaveObservation(permissionService: api.ObservationPermissionServ
2323 return async function saveObservation ( req : api . SaveObservationRequest ) : ReturnType < api . SaveObservation > {
2424 const repo = req . context . observationRepository
2525 const mod = req . observation
26- const before = await repo . findById ( mod . id )
27- const denied = before ?
28- await permissionService . ensureUpdateObservationPermission ( req . context ) :
29- await permissionService . ensureCreateObservationPermission ( req . context )
26+ const existingObservation = await repo . findById ( mod . id )
27+ const denied = existingObservation ?
28+ await permissionService . ensureUpdateObservationPermission ( req . context ) :
29+ await permissionService . ensureCreateObservationPermission ( req . context )
3030 if ( denied ) {
3131 return AppResponse . error ( denied )
3232 }
33- const obs = await prepareObservationMod ( mod , before , req . context )
33+ const obs = await prepareObservationMod ( mod , existingObservation , req . context )
3434 if ( obs instanceof MageError ) {
3535 return AppResponse . error ( obs )
3636 }
@@ -111,11 +111,11 @@ export function ReadAttachmentContent(permissionService: api.ObservationPermissi
111111 return AppResponse . error ( entityNotFound ( req . attachmentId , 'Attachment' ) )
112112 }
113113 const contentRange = typeof req . contentRange ?. start === 'number' && typeof req . contentRange . end === 'number' ?
114- { start : req . contentRange . start , end : req . contentRange . end } : void ( 0 )
114+ { start : req . contentRange . start , end : req . contentRange . end } : void ( 0 )
115115 let contentStream : NodeJS . ReadableStream | null | AttachmentStoreError = null
116116 let exoAttachment : api . ExoAttachment = api . exoAttachmentFor ( attachment )
117117 if ( typeof req . minDimension === 'number' ) {
118- const thumbIndex = thumbnailIndexForTargetDimension ( req . minDimension , attachment )
118+ const thumbIndex = thumbnailIndexForTargetDimension ( req . minDimension , attachment )
119119 const thumb = attachment . thumbnails [ Number ( thumbIndex ) ]
120120 if ( thumb ) {
121121 contentStream = await attachmentStore . readThumbnailContent ( thumb . minDimension , attachment . id , obs )
@@ -138,7 +138,7 @@ export function ReadAttachmentContent(permissionService: api.ObservationPermissi
138138 return AppResponse . success ( {
139139 attachment : exoAttachment ,
140140 bytes : contentStream ,
141- bytesRange : typeof req . minDimension === 'number' ? void ( 0 ) : contentRange
141+ bytesRange : typeof req . minDimension === 'number' ? void ( 0 ) : contentRange
142142 } )
143143 }
144144}
@@ -169,33 +169,33 @@ export function registerDeleteRemovedAttachmentsHandler(domainEvents: EventEmitt
169169 * an `isPending` property. That should be reasonable to implement, but no
170170 * time now, as usual.
171171 */
172- async function prepareObservationMod ( mod : api . ExoObservationMod , before : Observation | null , context : api . ObservationRequestContext ) : Promise < Observation | InvalidInputError > {
172+ async function prepareObservationMod ( mod : api . ExoObservationMod , observationToUpdate : Observation | null , context : api . ObservationRequestContext ) : Promise < Observation | InvalidInputError > {
173173 const event = context . mageEvent
174174 const repo = context . observationRepository
175- const modAttrs = baseObservationAttrsForMod ( mod , before , context )
175+ const modAttrs = baseObservationAttrsForMod ( mod , observationToUpdate , context )
176176 // first get new form entry ids so new attachments have a proper id to reference
177- const [ removedFormEntries , newFormEntries ] = mod . properties . forms . reduce ( ( [ removed , added ] , entryMod ) => {
178- if ( entryMod . id && before ?. formEntryForId ( entryMod . id ) ) {
177+ const [ removedFormEntries , newFormEntries ] = mod . properties . forms . reduce ( ( [ removed , added ] , entryMod ) => {
178+ if ( entryMod . id && observationToUpdate ?. formEntryForId ( entryMod . id ) ) {
179179 removed . delete ( entryMod . id )
180180 }
181181 else {
182182 added . push ( entryMod )
183183 }
184- return [ removed , added ]
185- } , [ new Map ( before ?. formEntries . map ( x => [ x . id , x ] ) || [ ] ) , [ ] as api . ExoFormEntryMod [ ] ] )
184+ return [ removed , added ]
185+ } , [ new Map ( observationToUpdate ?. formEntries . map ( x => [ x . id , x ] ) || [ ] ) , [ ] as api . ExoFormEntryMod [ ] ] )
186186 const newFormEntryIds = newFormEntries . length ? await repo . nextFormEntryIds ( newFormEntries . length ) : [ ]
187187 newFormEntries . forEach ( x => x . id = newFormEntryIds . shift ( ) )
188188 const attachmentExtraction = extractAttachmentModsFromFormEntries ( mod , event )
189189 modAttrs . properties . forms = attachmentExtraction . formEntries
190190 const attachmentMods = attachmentExtraction . attachmentMods
191191 const addCount = attachmentMods . reduce ( ( count , x ) => x . action === api . AttachmentModAction . Add ? count + 1 : count , 0 )
192192 const attachmentIds = addCount ? await repo . nextAttachmentIds ( addCount ) : [ ]
193- const afterRemovedFormEntryAttachments = before ?. attachments . reduce ( ( obs , attachment ) => {
193+ const afterRemovedFormEntryAttachments = observationToUpdate ?. attachments . reduce ( ( obs , attachment ) => {
194194 if ( removedFormEntries . has ( attachment . observationFormId ) ) {
195195 return removeAttachment ( obs , attachment . id ) as Observation
196196 }
197197 return obs
198- } , before )
198+ } , observationToUpdate )
199199 if ( afterRemovedFormEntryAttachments ) {
200200 modAttrs . attachments = afterRemovedFormEntryAttachments . attachments
201201 }
@@ -206,18 +206,17 @@ async function prepareObservationMod(mod: api.ExoObservationMod, before: Observa
206206 if ( obs instanceof MageError ) {
207207 return obs
208208 }
209- const mod =
210- attachmentMod . action === api . AttachmentModAction . Add ?
211- addAttachment ( obs , attachmentIds . shift ( ) as string , attachmentMod . fieldName , attachmentMod . formEntryId , attachmentCreateAttrsForMod ( attachmentMod ) ) :
212- attachmentMod . action === api . AttachmentModAction . Delete ?
213- removeAttachment ( obs , attachmentMod . id ) :
214- null
209+ let mod ;
210+ if ( attachmentMod . action === api . AttachmentModAction . Add ) {
211+ mod = addAttachment ( obs , attachmentIds . shift ( ) as string , attachmentMod . fieldName , attachmentMod . formEntryId , attachmentCreateAttrsForMod ( attachmentMod ) )
212+ } else if ( attachmentMod . action === api . AttachmentModAction . Delete ) {
213+ mod = removeAttachment ( obs , attachmentMod . id )
214+ } else {
215+ return invalidInput ( `invalid attachment action: ${ attachmentMod . action } ` )
216+ }
215217 if ( mod instanceof Observation ) {
216218 return mod
217219 }
218- if ( mod === null ) {
219- return invalidInput ( `invalid attachment action: ${ attachmentMod . action } ` )
220- }
221220 const message = `error adding attachment on observation ${ obs . id } `
222221 return invalidInput ( `${ message } : ${ String ( mod ) } ` )
223222 } , afterFormEntriesRemoved )
@@ -229,32 +228,33 @@ async function prepareObservationMod(mod: api.ExoObservationMod, before: Observa
229228 * existing observation. The result will not include form entries and
230229 * attachments, which require separate processing to resolve IDs and actions.
231230 * @param mod the modifications from an external client
232- * @param before the observation to update, or null if none exists
231+ * @param observationToUpdate the observation to update, or null if none exists
233232 */
234- function baseObservationAttrsForMod ( mod : api . ExoObservationMod , before : Observation | null , context : api . ObservationRequestContext ) : ObservationAttrs {
233+ function baseObservationAttrsForMod ( mod : api . ExoObservationMod , observationToUpdate : Observation | null , context : api . ObservationRequestContext ) : ObservationAttrs {
235234 const attrs : ObservationAttrs = {
236235 id : mod . id ,
237236 eventId : context . mageEvent . id ,
238- userId : before ? before . userId : context . userId ,
239- deviceId : before ? before . deviceId : context . deviceId ,
240- createdAt : before ? before . createdAt : new Date ( ) ,
237+ userId : observationToUpdate ? observationToUpdate . userId : context . userId ,
238+ deviceId : observationToUpdate ? observationToUpdate . deviceId : context . deviceId ,
239+ createdAt : observationToUpdate ? observationToUpdate . createdAt : new Date ( ) ,
241240 lastModified : new Date ( ) ,
242241 geometry : mod . geometry ,
243242 type : 'Feature' ,
244- states : before ? before . states : [ ] ,
245- bbox : mod . bbox || before ?. bbox ,
246- favoriteUserIds : before ?. favoriteUserIds || [ ] ,
247- important : before ?. important ,
243+ states : observationToUpdate ? observationToUpdate . states : [ ] ,
244+ bbox : mod . bbox || observationToUpdate ?. bbox ,
245+ favoriteUserIds : observationToUpdate ?. favoriteUserIds || [ ] ,
246+ important : observationToUpdate ?. important ,
248247 properties : {
249248 // TODO: should timestamp be optional on the mod object?
250249 timestamp : mod . properties . timestamp ,
251250 forms : [ ]
252251 } ,
253252 attachments : [ ] ,
253+ noGeometry : ! ! mod . noGeometry ,
254254 }
255- assignFirstDefined ( 'accuracy' , attrs . properties , mod . properties , before ?. properties )
256- assignFirstDefined ( 'delta' , attrs . properties , mod . properties , before ?. properties )
257- assignFirstDefined ( 'provider' , attrs . properties , mod . properties , before ?. properties )
255+ assignFirstDefined ( 'accuracy' , attrs . properties , mod . properties , observationToUpdate ?. properties )
256+ assignFirstDefined ( 'delta' , attrs . properties , mod . properties , observationToUpdate ?. properties )
257+ assignFirstDefined ( 'provider' , attrs . properties , mod . properties , observationToUpdate ?. properties )
258258 return attrs
259259}
260260
@@ -295,11 +295,11 @@ function extractAttachmentModsFromFormEntries(mod: api.ExoObservationMod, event:
295295function extractAttachmentModsFromFormEntry ( formEntryMod : api . ExoFormEntryMod , event : MageEvent ) : { formEntry : FormEntry , attachmentMods : QualifiedAttachmentMod [ ] } {
296296 const attachmentMods = [ ] as QualifiedAttachmentMod [ ]
297297 const { id, formId, ...fieldEntries } = formEntryMod as Required < api . ExoFormEntryMod >
298- const formEntry = Object . entries ( fieldEntries ) . reduce ( ( formEntry , [ fieldName , fieldEntry ] ) => {
298+ const formEntry = Object . entries ( fieldEntries ) . reduce ( ( formEntry , [ fieldName , fieldEntry ] ) => {
299299 const field = event . formFieldFor ( fieldName , formId )
300300 if ( field ?. type === FormFieldType . Attachment ) {
301301 const attachmentModEntry = ( fieldEntry || [ ] ) as api . ExoAttachmentMod [ ]
302- attachmentModEntry . forEach ( x => void ( x . action && attachmentMods . push ( { ...x , formEntryId : formEntry . id , fieldName } ) ) )
302+ attachmentModEntry . forEach ( x => void ( x . action && attachmentMods . push ( { ...x , formEntryId : formEntry . id , fieldName } ) ) )
303303 }
304304 else {
305305 // let it be invalid
0 commit comments