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

Duplicate UUIDs when same draft loaded multiple times #942

Open
jnm opened this issue Jun 16, 2023 · 3 comments
Open

Duplicate UUIDs when same draft loaded multiple times #942

jnm opened this issue Jun 16, 2023 · 3 comments
Labels

Comments

@jnm
Copy link
Member

jnm commented Jun 16, 2023

Describe the bug
If someone opens the same form more than once within the same browser session, and then loads the same draft in multiple tabs or windows, the submissions created from those drafts will have the same UUID.

To Reproduce
No special form is needed. I tested with a single decimal question.

  1. Open an offline-capable form
  2. Enter a response in a field and then click outside the field to change the focus
  3. This triggers saving an automatic draft (autosave successful in the console)
  4. Open the same offline-capable form in a new tab
  5. When prompted with "Unsaved Record Found", click "Load Record"
  6. Go back to the first tab and click submit
  7. Go the second tab and click submit
    • You can make edits to responses here before submitting and also reach the same outcome
  8. Result: two separate submissions with the same UUID are sent. This can be seen inside Enketo's IndexedDB properties, by looking at the submitted array within <survey ID>:stats

Expected behavior
The two submissions would have unique UUIDs.

Screenshots
image

Browser and OS (please complete the following information):

  • OS: Linux, Windows, Android
  • Browser: Chrome, Firefox

Additional context

The same is true for named drafts (created with the "Save Draft") button as well as autosaved drafts.

I identified this code path for UUID generation:

  1. Initial page load in offline-capable mode:
    1. https://github.com/enketo/enketo-express/blob/6.1.0/public/js/src/enketo-webform.js#L29-L40
    2. https://github.com/enketo/enketo-express/blob/6.1.0/public/js/src/enketo-webform.js#L239-L250
  2. Form initialization:
    1. https://github.com/enketo/enketo-express/blob/6.1.0/public/js/src/module/controller-webform.js#L105
    2. https://github.com/enketo/enketo-core/blob/7.2.3/src/js/form.js#L332
  3. Generation of UUID (only if none has been set already):
    1. https://github.com/enketo/enketo-core/blob/7.2.3/src/js/preload.js#L170-L179

For loading a (named) draft:

  1. https://github.com/enketo/enketo-express/blob/6.1.0/public/js/src/module/controller-webform.js#L808-L814
  2. https://github.com/enketo/enketo-express/blob/6.1.0/public/js/src/module/controller-webform.js#L270-L307
  3. Then proceeds with "Form initialization" as listed above, which will not regenerate the UUID
@jnm jnm added bug Something isn't working offline-only labels Jun 16, 2023
@lognaturel
Copy link
Contributor

lognaturel commented Jun 17, 2023

I agree there’s a problem here. Users do open a draft in one tab, forget about it, open it in another tab as well, and end up in an inconsistent state. That said, I think the current behavior is consistent with a draft concept without any kind of edit lock.

What you describe feels more like a “clone and complete.” Is that the goal you have? You want to be able to partially fill out a record and then spin off clones that actually represent different submissions? If you start with one locally-saved record, open it in 5 tabs, save each, would you expect 5 or 6 local records with this feature?

@jnm
Copy link
Member Author

jnm commented Jun 19, 2023

Users do open a draft in one tab, forget about it, open it in another tab as well, and end up in an inconsistent state.

Right, I think this is the main problem. Maybe power users are doing "clone and complete"—and I'm trying to find out—but I'm mostly concerned about people accidentally getting into a state where they are unknowingly sending duplicate UUIDs. One project I was investigating had 15% of its submissions contain duplicate UUIDs.

You want to be able to partially fill out a record and then spin off clones that actually represent different submissions? If you start with one locally-saved record, open it in 5 tabs, save each, would you expect 5 or 6 local records with this feature?

I would be happy if Enketo blocked me from opening that one locally-saved record in more than one tab simultaneously. That kind of locking feels elegant, but I don't know how much of a pain it would be to implement.

Other use cases are interesting, but I don't see them as part of this bug report. I would like to prioritize preventing Enketo from reusing the same UUID when sending submissions with disparate response data. I think Central has always had good hygiene by rejecting duplicate UUIDs with HTTP 409, blocking "clone and complete" as someone might attempt it with today's Enketo. Kobo has been very permissive and accepted almost anything that a client would send, but we are tightening things up because we increasingly rely on the UUID being a truly unique identifier.

Thanks for responding so quickly, and I look forward to reading your thoughts.

@eyelidlessness
Copy link
Collaborator

I believe this is solvable without locking, by moving this offline storage logic to the offline service worker, because there’s only ever a single instance of a service worker running at any given time, regardless of how many open tabs depend on it.

This dovetails well with other ongoing work to move several other offline storage concerns—for instance, caching of media (#464) and forms—to the service worker as well, so we’ll probably address this in that context/scope.

These changes, especially combined, will also allow us to significantly reduce the complexity of offline-capable mode.

I’ll be on vacation over the next month, but I intend to pick this back up when I get back.

@lognaturel lognaturel transferred this issue from enketo/enketo-express Nov 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants