Commit graph

94 commits

Author SHA1 Message Date
Dan Stillman
ae98136ec8 Save uploaded objects to the sync cache on an unchanged response
The cache-existence check didn't await getCacheObject(), so the
promise was always truthy and no cache object was ever saved for
objects the server reported as unchanged. Without a cached version,
later remote changes to those objects produced avoidable conflicts.
2026-07-29 00:06:42 -04:00
Dan Stillman
37bf9d0965 Trigger full sync when server library version goes backward
Some checks are pending
CI / Build, Upload, Test (push) Waiting to run
When a user's account is deleted and then undeleted on the server, the
dataserver creates a fresh shardLibraries row at a low version, while the
client still has a much higher local library version. Subsequent syncs
then throw "_libraryVersion cannot decrease" and the user is stuck.

Tag the cannot-decrease errors from the library version setters with a
named error, catch it in Engine.start(), reset libraryVersion and
storageVersion to -1, and restart. The retry hits the existing
libraryVersion == -1 branch and runs _fullSync(), which re-uploads the
local library against the recreated server library.
2026-05-20 23:11:35 -04:00
Dan Stillman
3f0de027a2 Auto-resolve lastRead sync conflicts by picking the most recent value 2026-04-07 10:29:25 -04:00
Dan Stillman
391e8497a6 Handle per-object 403 on settings upload and reset to remote version
If the server returns a write report with 403 for admin-only settings,
mark successful settings as synced and reset rejected settings to
their remote values by re-downloading from the server.

Needed for #5862
2026-03-26 15:54:28 -04:00
Dan Stillman
eb3a136ccd Use new batch setting deletion API endpoint
Use DELETE /settings?settingKey=key1,key2 instead of individual DELETE
per key, with batching matching uploadDeletionBatchSize.
2026-03-20 15:43:03 -04:00
Dan Stillman
35713fefd0 Upload setting deletions during sync
Deleted settings were written to syncDeleteLog but never uploaded. Add
dedicated setting deletion upload in _startUpload() using individual
DELETE requests per setting, since the API doesn't support batch setting
deletion.
2026-03-20 11:25:27 -04:00
Dan Stillman
20735c425f
Add resetData() as lightweight alternative to resetDB() for sync tests (#5822)
resetData() clears user data and sync state using application APIs
instead of doing a full Zotero shutdown/reinit cycle, making it much
faster for tests that just need clean state between runs.

Also make Tags.init(), Creators.init(), Users.init(), and
SyncedSettings.loadAll() properly clear their caches before reloading,
so they are safe to call more than once.
2026-03-05 15:54:10 -05:00
Dan Stillman
bf59a1e2f8 Revert "Fix relations to erased items reappearing after sync (#5486)"
I think this might cause problems and needs to be tested further.

This reverts commit 07066fd8c1.
2025-08-15 02:09:18 -04:00
abaevbog
07066fd8c1
Fix relations to erased items reappearing after sync (#5486)
Fix ghost relations to erased items reappearing after
sync. The dataserver ensures that related relations are
bidirectional. If a related item is erased, syncing
would first upload the update to the remaining related item
(where the relation is removed), followed by the deletions.
While handling update upload, the dataserver would return
the old, should-be-removed, "dc:relation" entry for that item
because it does not know that the other item is erased.

To handle this, swap the order of operations during sync:
upload deletion first and then upload updates after.
Then, when the dataserver handles the update of the non-erased item,
there is no related item to enforce bidirectional relations to.

Fixes: #5481
2025-08-15 02:00:43 -04:00
Dan Stillman
5063a8b396 isAboveisAtLeast in sync engine tests for testing delays
Maybe related to Bluebird?
2025-07-31 10:45:19 -04:00
Dan Stillman
f81763b173 Remove Chai as Promised
A test using `assert.eventually` was failing after the Bluebird removal
but worked with just `await`, and since there hasn't really been much
point to Chai as Promised since the introduction of `async`/`await` ages
ago, just remove the library instead of figuring out why.
2025-07-30 22:31:08 -04:00
Abe Jellinek
67d2e1cead fx140: Asyncify/ESMify tests
They seem to be succeeding when run individually, but failing when
run as a whole. Not sure why yet.
2025-07-30 22:30:53 -04:00
Abe Jellinek
ece2b59700 fx140: More progress toward startup 2025-07-30 22:18:36 -04:00
Dan Stillman
17539404b2 Fix test failure calling item.toResponseJSON() with no library set
After #4270
2024-06-12 05:50:36 -04:00
Dan Stillman
24ae341045 Fix test breakage from f68818387 2023-09-18 16:47:55 -04:00
Dan Stillman
f21ca49d83 Fix sync engine tests after 00703c0b8 2023-05-05 06:38:00 -04:00
Dan Stillman
4a77bc4be0 fx-compat: Update conflict resolution merge window (#3090)
Tests passing, but not yet styled properly
2023-04-29 03:13:53 -04:00
Dan Stillman
4a30dd2e4f Fix potential sync error after Replace Online Library in group
https://forums.zotero.org/discussion/104431/syncing-problem

Replace Online Library can upload annotations created by others in a
group library, so if the upload resulted in a local write, "Cannot edit
item in library" was thrown, since annotations by others aren't
writable. This should've only been a problem if the uploaded data was
actually modified by the server, but we were also checking whether
objects were editable before checking if they had actually changed, so
it would happen for any upload of another person's annotation.

This fixes the order of checks when saving objects and makes an
edit-check exception for saving uploaded data for group annotations.
2023-04-21 06:51:25 -04:00
Dan Stillman
72ac453a8c Set createdByUserID to current user for locally created group item
Addresses #2322
2022-02-19 13:47:28 -05:00
Dan Stillman
644c4e5925 Add objects from failed download requests to sync queue
Previously only individual objects from successful requests that
couldn't be processed for some reason would be added to the queue.

`Sync.APIClient.downloadObjects()` now returns clearer and more
consistent results. It now returns an array of promises for objects with
a `keys` array of requested keys and either a `json` array of returned
API JSON objects or an `error` Error, depending on whether the request
succeeded or failed. This makes it easier to detect remotely missing
objects and request failures.
2021-12-10 05:56:46 -05:00
Dan Stillman
f5eb99ad4c Upload settings in batches of 250
Closes #2000
2021-11-07 23:46:54 -05:00
Dan Stillman
06b28194da Show annotation widget in conflict resolution window
This adds a very basic reimplementation of the annotation widget for use
in the CR window. It's not pixel-perfect, but it's close enough that
most people probably won't notice. We'll want to replace this with a
real version that's shared between the PDF reader and the rest of the
codebase.

Image annotations currently show an "[image not shown]" placeholder.
Showing images is tricky: we don't have the remote cache image, so if
the remote position has changed, we could only show an image by
rendering it from the file, and only if the file itself hasn't changed.
Just for a better user experience, we could use the local image as long
as the position and file are both the same, but that would take some
rejiggering of the CR window.

Tags aren't shown because they're not shown for CR at all, though that
could be changed in the future.
2021-03-21 14:36:43 -04:00
Dan Stillman
9204e18ee3 Fix sync test after removing format=json from syncAPIClient 2021-03-03 06:42:08 -05:00
Dan Stillman
ebc0ca2462 Add annotationIsExternal property to annotations 2021-03-02 17:58:28 -05:00
Dan Stillman
a94323fc15 Sort multiple levels of items when generating API JSON
Added Zotero.DataObjects.sortByParent() to sort child items immediately
after their parent items. Zotero.DataObjects.sortByLevel(), which is
used for collections, sorts each level together, but that's less
appropriate for items where, e.g., an embedded-image attachment should
immediately follow the note that depends on it.
2021-03-02 17:36:05 -05:00
Dan Stillman
4142f4b316 Replace occurrences of .getNote() with .note 2021-03-02 17:36:05 -05:00
Dan Stillman
b54d4e78b7 Save createdByUserID and lastModifiedByUserID for group items 2021-03-02 17:36:04 -05:00
Dan Stillman
cca5dc0314 Don't send unnecessary format=json in sync download requests 2021-03-02 17:36:04 -05:00
Dan Stillman
b919143630 Skip conflict resolution for remote objects that can't be saved
E.g., if a local item has been modified in a way that conflicts with a
remote item that also has a new, unknown field, don't show the CR
window -- just add the item to the sync queue and show the
some-data-could-not-be-downloaded error.
2021-02-07 16:49:01 -05:00
Dan Stillman
ad13313924 Don't change existing sync cache object on 'unchanged' response
Previously, if an object was uploaded but the API returned 'unchanged',
the uploaded data would be written to the sync cache, which, given that
most requests are patch requests, could result in an empty or mostly
empty object being saved to the sync cache. That would cause the next
sync to treat most/all local fields as changed and either upload them
unnecessarily or trigger a conflict instead of merging changes
automatically.
2020-04-14 05:07:50 -04:00
Dan Stillman
d4f682aa88 Merge branch 'fx60' 2019-10-21 21:44:01 -04:00
Dan Stillman
4b7cdddb4a Change apply-to-all checkbox text for some conflicts
Say "Use the [local|remote] version for all remaining conflicts" for
everything instead of saying "Use [local|remote] fields for all
remaining conflicts" for some conflicts.

This also fixes a test failure after 54343c49fb.
2019-09-21 01:35:36 -04:00
Dan Stillman
4b60c6ca27 Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.

Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.

When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.

For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.

For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.

[1] https://github.com/zotero/zotero-schema
2019-09-16 02:27:22 -04:00
Dan Stillman
f04f186396 Add missing yield in sync code 2019-09-16 00:47:45 -04:00
Dan Stillman
985f10d5ed Fix WebDAV test after 1f1b2e9b2 2019-06-03 03:35:32 -04:00
Dan Stillman
c0e2aa03d3 Fix test for delay after second library version conflict 2019-05-31 02:44:41 -04:00
Dan Stillman
9a304b6699 Better handling of remotely changed items in locally missing collections 2018-04-07 17:04:35 -04:00
Dan Stillman
ac4abf0ebb Avoid race conditions in conflict resolution tests 2018-04-07 17:04:00 -04:00
Dan Stillman
c0b63e5928 Better handling of 403 for attachment metadata upload
Check file-editing access for the group from the API before offering to
reset, update the filesEditable setting properly, and restart the sync
automatically after resetting.
2018-02-23 17:59:32 -05:00
Dan Stillman
c5fa1303e3 Prompt to reset local group files on 403 for file attachment upload
And reset modified file attachments when resetting files
2018-01-26 03:37:57 -05:00
Dan Stillman
d67c654245 Add version option to toResponseJSON() 2018-01-26 03:37:57 -05:00
Dan Stillman
df38f4ded7 Avoid upload retry loops
- Don't try uploading an object more than 5 times
- Don't retry a child item if the parent item failed too
2017-12-10 03:45:08 -05:00
Dan Stillman
f353b7ca61 API-based "Restore to Online Library"
Restores the "Restore to Zotero Server" functionality, now using the
API:

1. Get all remote keys and send `DELETE` for any that don't exist
   locally.
2. Upload all local objects in full (non-patch) mode using only library
   version so that the remotes are overwritten.
3. Reset file sync history, causing all files to be uploaded (or, more
   likely, reassociated with existing remote files).

Since these are treated as regular updates on the server, they'll sync
down to other clients normally. Unsynced changes by other clients might
still trigger conflicts.

This and Reset File Sync History can also now be run on group libraries,
with a library selector in the Reset pane (which I forgot to do with
React).

The full sync option is now removed from the Reset pane, since there
wasn't ever really a reason to run it manually.

We should be able to reimplement Restore from Online Library (#1386)
using the inverse of this approach.

Closes #914
2017-12-08 00:42:03 -05:00
Dan Stillman
34028d354e Don't try to delete Quick Start Guide items in test
We don't create these items anymore.
2017-10-27 01:09:34 -04:00
Dan Stillman
f0770fa84d Fix various conflict resolution bugs
Among other things, when choosing the local side for a conflict, the
remote version could still end up being saved.
2017-10-27 01:08:38 -04:00
Dan Stillman
d81e2a5cf0 Fix sync errors from remote item referencing deleted local collection 2017-09-20 05:33:44 -04:00
Dan Stillman
9069559050 Improve logic for determining whether to check for files to download
This should fix cases of files not being downloaded after interrupted
syncs until the next time files were changed remotely.
2017-08-11 22:29:40 +02:00
Dan Stillman
47741e75fa Restore locally deleted collections and searches that changed remotely
Also restore items that were in the collections
2017-06-18 09:11:21 -04:00
Dan Stillman
40da5f61a0 Still process downloads if uploads fail for a library 2017-05-05 03:26:29 -04:00
Dan Stillman
a1bd2bace5 Remove objects from sync queue if missing from response
While objects in the sync queue that fail to save should remain in the
queue, objects that just don't exist remotely need to be removed, or
else they'll be retried forever.
2017-05-05 01:04:16 -04:00