mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
Fixes from the review of the Files work (1cf9944b..a9a25b94).
- A file shared on its own, or one below a folder its owner took back,
could not be reached. Once Stalwart 1.0's placeholder folders were
left out it became a root of "Shared with me", which listed folders
only, and search opened it on the drive root. 0.16 lists such files
as roots too. Each owner's files shared on their own are now listed
on one page under "Shared with me" ("Files from <name>"), where they
open, preview and download like any other file and nothing can be
added; two of the same name get a number. Search opens a shared hit
where it is listed, and links into a shared drive name the node by id
(`/files?shared=<owner>:<id>`), so a shared folder or page also
survives a reload. A Files page that is already open takes the link
from search directly, since Next keeps it mounted when only the query
changes.
- A copy that fails part-way destroys only the nodes it made, the
deepest first and without `onDestroyRemoveChildren`, one call per
level because 0.16 refuses a folder destroyed in the same call as
its children. It used to destroy the new folder with everything
below it, so whatever someone put there during a long copy was
deleted for good. A folder holding such nodes now stays, and the
error says part of the copy was left in place.
- The document editor opens read-only on 0.16 for a sharee without the
rename right. 0.16.6 to 0.16.23 refuse any change a sharee makes
without Modify, so every save of such a document failed with a 500.
1.0, told apart by its `maxFileNodeDepth`, still asks for
`mayModifyContent` alone.
- Ctrl+C with only symlinks selected empties the clipboard instead of
keeping an earlier cut for the next paste.
- A paste reads each account's file tree once, not once per pasted
item for the listing and 1.0's depth check.
- The Stalwart bundle's README says that on older 0.16 releases and
the 1.0 pre-releases a failed update also drops the cached copy, and
the next restart or reload of the Applications downloads it again,
not only a later `UpdateApps`. The static README says a restart
applies the CORS setting on the current 1.0 pre-releases, where
`ReloadSettings` fails with the stock spam-filter rules.
54 lines
3.2 KiB
TypeScript
54 lines
3.2 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { fileErrorKind, folderDepthError, isPartialCopy, partialCopyError } from '../file-errors';
|
|
import { jmapError } from '../jmap/jmap-error';
|
|
|
|
// SetErrors as Stalwart words them (1.0: jmap/src/file/*.rs; 0.16.23:
|
|
// jmap/src/file/set.rs), thrown by the JMAP client through jmapError.
|
|
const setError = (type: string, description: string, properties?: string[]) =>
|
|
jmapError(description, { type, description, properties });
|
|
|
|
describe('fileErrorKind', () => {
|
|
it('explains Stalwart 1.0\'s limits on files and folders', () => {
|
|
expect(fileErrorKind(setError('overQuota', 'There are too many files, please delete some before adding a new one.'))).toBe('overQuota');
|
|
expect(fileErrorKind(setError('overQuota', 'There are too many folders, please delete some before adding a new one.'))).toBe('overQuota');
|
|
expect(fileErrorKind(setError('invalidProperties', 'Maximum folder depth exceeded.', ['parentId']))).toBe('tooDeep');
|
|
expect(fileErrorKind(setError('tooLarge', 'File is too large.'))).toBe('tooLarge');
|
|
});
|
|
|
|
it('treats Bulwark\'s own depth check like the server\'s', () => {
|
|
expect(fileErrorKind(folderDepthError())).toBe('tooDeep');
|
|
});
|
|
|
|
it('explains refused names on 0.16 and 1.0', () => {
|
|
expect(fileErrorKind(setError('invalidProperties', 'Name is reserved and cannot be used.', ['name']))).toBe('invalidName');
|
|
expect(fileErrorKind(setError('invalidProperties', 'Name contains a forbidden character.', ['name']))).toBe('invalidName');
|
|
expect(fileErrorKind(setError('invalidProperties', 'Name must be between 1 and 255 octets.', ['name']))).toBe('invalidName');
|
|
});
|
|
|
|
it('explains missing rights on 0.16 and 1.0', () => {
|
|
expect(fileErrorKind(setError('forbidden', 'You are not allowed to create file nodes in this folder.'))).toBe('forbidden');
|
|
expect(fileErrorKind(setError('forbidden', 'You do not have access to blobId b2.'))).toBe('forbidden');
|
|
expect(fileErrorKind(setError('forbidden', 'You are not allowed to modify this file node.'))).toBe('forbidden');
|
|
});
|
|
|
|
it('keeps why a copy stopped when part of it was left in place', () => {
|
|
const cause = setError('overQuota', 'There are too many files, please delete some before adding a new one.');
|
|
const partial = partialCopyError(cause);
|
|
expect(isPartialCopy(partial)).toBe(true);
|
|
expect(fileErrorKind(partial)).toBe('overQuota');
|
|
expect(partial.message).toBe(cause.message);
|
|
expect(fileErrorKind(partialCopyError(folderDepthError()))).toBe('tooDeep');
|
|
expect(isPartialCopy(partialCopyError(new TypeError('Failed to fetch')))).toBe(true);
|
|
expect(isPartialCopy(cause)).toBe(false);
|
|
});
|
|
|
|
it('has nothing to add for other errors', () => {
|
|
// The folder is gone, or a folder was moved into itself.
|
|
expect(fileErrorKind(setError('invalidProperties', 'Parent ID does not exist or is not a folder.', ['parentId']))).toBeNull();
|
|
expect(fileErrorKind(setError('invalidProperties', 'Circular reference in parent ids.', ['parentId']))).toBeNull();
|
|
expect(fileErrorKind(setError('notFound', 'Not found'))).toBeNull();
|
|
expect(fileErrorKind(new Error('Failed to upload file: 500'))).toBeNull();
|
|
expect(fileErrorKind(undefined)).toBeNull();
|
|
});
|
|
});
|