fix(import): restore favorite + pinned on import/backup restore
A pinned entry came back unpinned after export→import. Wider than pinned: `favorite` was WRITTEN into the export/backup/sync containers but nothing ever read it back — not parseEntriesFromJSON, not encryptImportEntry, not the server INSERTs. So it was a write-only field, and a restore silently dropped both flags. `pinned` wasn't in any container at all. Wired the full round-trip: - containers: export + auto-backup now carry `pinned` (favorite was there). - parseEntriesFromJSON reads both back (absent → 0, e.g. foreign CSV). - encryptImportEntry passes them through to the body. - server create + bulk-import INSERTs write favorite/pinned (GetValue<Boolean>(..., False) → 0 default). PUT still ignores them, so a sync update can't clobber local flags. Sync stays device-local as decided 2026-07-11: buildSyncSnapshot now OMITS favorite explicitly (it was dead weight before; with the passthrough live, leaving it in would have started propagating it). Commented so the intent isn't re-broken. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -333,7 +333,7 @@ var
|
||||
LTotpSec, LTotpIv, LKind, LCf, LCfIv, LIcon, LUuid,
|
||||
LTemplateEnc, LTemplateIv, LCreatedAt, LUpdatedAt,
|
||||
LSiteEnc, LSiteIv, LTitleEnc, LTitleIv, LTagsEnc, LTagsIv: string;
|
||||
LIconCustom: Boolean;
|
||||
LIconCustom, LFavorite, LPinned: Boolean;
|
||||
LQ: TFDQuery;
|
||||
begin
|
||||
try
|
||||
@@ -374,6 +374,9 @@ begin
|
||||
LIcon := LBody.GetValue<string>('icon_b64', '');
|
||||
// Icon provenance (0 = fetched cache, 1 = user upload). Absent → 0.
|
||||
LIconCustom := LBody.GetValue<Boolean>('icon_custom', False);
|
||||
// Restore flags (import/backup carry them; sync omits them → 0).
|
||||
LFavorite := LBody.GetValue<Boolean>('favorite', False);
|
||||
LPinned := LBody.GetValue<Boolean>('pinned', False);
|
||||
LTemplateEnc := LBody.GetValue<string>('template_enc', '');
|
||||
LTemplateIv := LBody.GetValue<string>('template_iv', '');
|
||||
// Caller may bring its own UUID (sync restore / import preserving
|
||||
@@ -415,10 +418,10 @@ begin
|
||||
' site_enc, site_iv, title_enc, title_iv, tags_enc, tags_iv, ' +
|
||||
' encrypted_password, iv, encryption_method, ' +
|
||||
' folder, totp_secret, totp_iv, kind, custom_fields, custom_fields_iv,' +
|
||||
' icon_b64, icon_custom, template_enc, template_iv, uuid, created_at, updated_at, password_changed_at) ' +
|
||||
' icon_b64, icon_custom, favorite, pinned, template_enc, template_iv, uuid, created_at, updated_at, password_changed_at) ' +
|
||||
'VALUES (:uid, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' +
|
||||
' :e, :i, ''client'', :f, :ts, :tiv, :k, ' +
|
||||
' :cf, :cfiv, :ic, :iconcust, :tplenc, :tpliv, :uuid, :c, :c2, :c)';
|
||||
' :cf, :cfiv, :ic, :iconcust, :fav, :pin, :tplenc, :tpliv, :uuid, :c, :c2, :c)';
|
||||
LQ.ParamByName('uid').AsInteger := LUserId;
|
||||
// site/username/title/tags cleartext columns dropped — only *_enc written.
|
||||
BindNullable(LQ, 'uenc', LUserEnc);
|
||||
@@ -457,6 +460,10 @@ begin
|
||||
if LIcon = '' then LQ.ParamByName('ic').Clear else LQ.ParamByName('ic').Value := LIcon;
|
||||
if (LIcon <> '') and LIconCustom then LQ.ParamByName('iconcust').AsInteger := 1
|
||||
else LQ.ParamByName('iconcust').AsInteger := 0;
|
||||
if LFavorite then LQ.ParamByName('fav').AsInteger := 1
|
||||
else LQ.ParamByName('fav').AsInteger := 0;
|
||||
if LPinned then LQ.ParamByName('pin').AsInteger := 1
|
||||
else LQ.ParamByName('pin').AsInteger := 0;
|
||||
BindNullable(LQ, 'tplenc', LTemplateEnc);
|
||||
BindNullable(LQ, 'tpliv', LTemplateIv);
|
||||
LQ.ParamByName('uuid').AsString := LUuid;
|
||||
@@ -1208,7 +1215,7 @@ var
|
||||
LTotpIv, LNow, LKind, LCf, LCfIv, LIcon, LTemplateEnc, LTemplateIv, LUuid,
|
||||
LCreatedAt, LUpdatedAt,
|
||||
LSiteEnc, LSiteIv, LTitleEnc, LTitleIv, LTagsEnc, LTagsIv: string;
|
||||
LIconCustom: Boolean;
|
||||
LIconCustom, LFavorite, LPinned: Boolean;
|
||||
LQ, LTomb: TFDQuery;
|
||||
begin
|
||||
try
|
||||
@@ -1265,10 +1272,10 @@ begin
|
||||
' site_enc, site_iv, title_enc, title_iv, tags_enc, tags_iv, ' +
|
||||
' encrypted_password, iv, encryption_method, ' +
|
||||
' folder, totp_secret, totp_iv, kind, custom_fields, custom_fields_iv,' +
|
||||
' icon_b64, icon_custom, template_enc, template_iv, uuid, created_at, updated_at) ' +
|
||||
' icon_b64, icon_custom, favorite, pinned, template_enc, template_iv, uuid, created_at, updated_at) ' +
|
||||
'VALUES (:uid, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' +
|
||||
' :e, :i, ''client'', :f, :ts, :tiv, :k, ' +
|
||||
' :cf, :cfiv, :ic, :iconcust, :tplenc, :tpliv, :uuid, :c, :c2)';
|
||||
' :cf, :cfiv, :ic, :iconcust, :fav, :pin, :tplenc, :tpliv, :uuid, :c, :c2)';
|
||||
// Declare optional param types ONCE — the prepared statement is
|
||||
// reused across every imported entry, and FireDAC needs the
|
||||
// type set before the first .Clear call would otherwise fail
|
||||
@@ -1317,6 +1324,8 @@ begin
|
||||
LCfIv := LEntry.GetValue<string>('custom_fields_iv', '');
|
||||
LIcon := LEntry.GetValue<string>('icon_b64', '');
|
||||
LIconCustom := LEntry.GetValue<Boolean>('icon_custom', False);
|
||||
LFavorite := LEntry.GetValue<Boolean>('favorite', False);
|
||||
LPinned := LEntry.GetValue<Boolean>('pinned', False);
|
||||
LTemplateEnc := LEntry.GetValue<string>('template_enc', '');
|
||||
LTemplateIv := LEntry.GetValue<string>('template_iv', '');
|
||||
LUuid := Trim(LEntry.GetValue<string>('uuid', ''));
|
||||
@@ -1362,6 +1371,10 @@ begin
|
||||
if LIcon = '' then LQ.ParamByName('ic').Clear else LQ.ParamByName('ic').Value := LIcon;
|
||||
if (LIcon <> '') and LIconCustom then LQ.ParamByName('iconcust').AsInteger := 1
|
||||
else LQ.ParamByName('iconcust').AsInteger := 0;
|
||||
if LFavorite then LQ.ParamByName('fav').AsInteger := 1
|
||||
else LQ.ParamByName('fav').AsInteger := 0;
|
||||
if LPinned then LQ.ParamByName('pin').AsInteger := 1
|
||||
else LQ.ParamByName('pin').AsInteger := 0;
|
||||
BindNullable(LQ, 'tplenc', LTemplateEnc);
|
||||
BindNullable(LQ, 'tpliv', LTemplateIv);
|
||||
LQ.ParamByName('uuid').AsString := LUuid;
|
||||
|
||||
Reference in New Issue
Block a user