feat(app): wire server dedup - force passthrough + PHOTO_DUPLICATE classification & l10n
Task 8: close the gap between server-side duplicate detection (90dcc58)
and the app.
- ApiClient.mapDioException: normalize 409 wire body reusing
VALIDATION_FAILED with message=PHOTO_DUPLICATE to
ErrorCodes.photoDuplicate (message-based; auto-compat if the contract
later adds a dedicated code)
- l10n zh/en errorPhotoDuplicate; error_l10n maps the code (queue page
inherits via fallback)
- UploadEngine._classifyFailure: PHOTO_DUPLICATE joins the no-auto-retry
bucket (retrying the same init body would 409 again); force to skip
dedup travels only through the enqueue path
- UploadTasks drift table +force column (schema v2, addColumn migration;
legacy rows default false); UploadTaskDraft/UploadTask/prepare carry it
- enqueueForUpload +forcePaths; duplicate dialog "全部上传" (capture page
+ album detail page) now returns DuplicateDialogChoice so confirmed
duplicates enqueue with force=true (server adjudicates owner/admin)
- engine init body carries force only when true (absent otherwise)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -87,7 +87,9 @@ class UploadPreparer {
|
||||
/// 准备一张图片并入队。
|
||||
///
|
||||
/// [sourcePath] 为 image_picker/camera 返回的源文件路径(App 沙箱内
|
||||
/// 可直接 File 读取);[filename] 缺省取源文件 basename。
|
||||
/// 可直接 File 读取);[filename] 缺省取源文件 basename;[force] 为
|
||||
/// 查重弹窗「全部上传」的用户确认(Task 8)——落到任务行,由引擎在
|
||||
/// initUpload 携带(仅 owner/admin 生效,服务端裁决)。
|
||||
///
|
||||
/// 返回入队后的任务(state=queued);失败返回 state=preparationFailed
|
||||
/// 的任务(不抛异常——准备失败是业务状态而非调用错误)。
|
||||
@@ -97,6 +99,7 @@ class UploadPreparer {
|
||||
String? categoryId,
|
||||
required String sourcePath,
|
||||
String? filename,
|
||||
bool force = false,
|
||||
}) {
|
||||
return _runBounded(
|
||||
() => _prepare(
|
||||
@@ -105,6 +108,7 @@ class UploadPreparer {
|
||||
categoryId: categoryId,
|
||||
sourcePath: sourcePath,
|
||||
filename: filename,
|
||||
force: force,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -164,6 +168,7 @@ class UploadPreparer {
|
||||
required String? categoryId,
|
||||
required String sourcePath,
|
||||
required String? filename,
|
||||
required bool force,
|
||||
}) async {
|
||||
final id = _newId();
|
||||
final clientTaskId = _newId();
|
||||
@@ -188,6 +193,7 @@ class UploadPreparer {
|
||||
// 预检失败时占位(该行永不进入传输;成功路径 bytes 来自源 stat)。
|
||||
bytes: bytes > 0 ? bytes : 1,
|
||||
contentType: contentType ?? 'application/octet-stream',
|
||||
force: force,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user