83 lines
2.8 KiB
Dart
83 lines
2.8 KiB
Dart
/// Nextcloud share permission bitmask helpers. These mirror the constants the
|
|
/// OCS `files_sharing` API expects in the `permissions` field. Kept as pure
|
|
/// functions (no Flutter/IO) so they are unit-testable.
|
|
library;
|
|
|
|
/// Individual permission bits (Nextcloud `OCS\Constants`).
|
|
const int kPermissionRead = 1;
|
|
const int kPermissionUpdate = 2;
|
|
const int kPermissionCreate = 4;
|
|
const int kPermissionDelete = 8;
|
|
const int kPermissionShare = 16;
|
|
|
|
/// User-facing presets that map onto a bitmask.
|
|
enum SharePreset {
|
|
/// Recipient can only view/download.
|
|
readOnly,
|
|
|
|
/// Recipient can view, edit, add and remove (full editing).
|
|
edit,
|
|
|
|
/// Upload-only "file request" — recipient can add files to a folder but not
|
|
/// see existing contents. Only meaningful for folders.
|
|
fileDrop,
|
|
}
|
|
|
|
extension SharePresetLabel on SharePreset {
|
|
String get label {
|
|
switch (this) {
|
|
case SharePreset.readOnly:
|
|
return 'Nur Lesen';
|
|
case SharePreset.edit:
|
|
return 'Bearbeiten';
|
|
case SharePreset.fileDrop:
|
|
return 'Datei-Anfrage';
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns true if [mask] contains the given [flag].
|
|
bool hasPermission(int mask, int flag) => mask & flag == flag;
|
|
|
|
/// Builds the permission bitmask for a [preset].
|
|
///
|
|
/// [isFolder] matters for the `edit` preset: a file can only carry
|
|
/// read+update, while a folder additionally supports create+delete. Nextcloud
|
|
/// rejects create/delete on a file ("Failed to update share"), so they must be
|
|
/// omitted there. When [allowReshare] is true the reshare bit is added to the
|
|
/// editing presets — mirroring how the Nextcloud clients respect the
|
|
/// `resharing` capability.
|
|
int permissionsFor(
|
|
SharePreset preset, {
|
|
bool allowReshare = false,
|
|
bool isFolder = false,
|
|
}) {
|
|
switch (preset) {
|
|
case SharePreset.readOnly:
|
|
return kPermissionRead;
|
|
case SharePreset.edit:
|
|
var base = kPermissionRead | kPermissionUpdate;
|
|
if (isFolder) base |= kPermissionCreate | kPermissionDelete;
|
|
return allowReshare ? base | kPermissionShare : base;
|
|
case SharePreset.fileDrop:
|
|
return kPermissionCreate;
|
|
}
|
|
}
|
|
|
|
/// Classifies an arbitrary permission bitmask into the closest preset, or null
|
|
/// if it doesn't match any (e.g. a custom combination). The reshare bit is
|
|
/// ignored for matching so an "edit" share stays "edit" regardless of reshare.
|
|
SharePreset? presetFromBitmask(int mask) {
|
|
final normalized = mask & ~kPermissionShare;
|
|
if (normalized == kPermissionCreate) return SharePreset.fileDrop;
|
|
if (normalized == kPermissionRead) return SharePreset.readOnly;
|
|
// Any read share that also carries a write bit (update/create/delete) is
|
|
// surfaced as "edit".
|
|
const writeBits = kPermissionUpdate | kPermissionCreate | kPermissionDelete;
|
|
if (hasPermission(normalized, kPermissionRead) &&
|
|
normalized & writeBits != 0) {
|
|
return SharePreset.edit;
|
|
}
|
|
return null;
|
|
}
|