Skip to content

Commit

Permalink
PS-713 databox privacy widget: fix collection inheritance constraint
Browse files Browse the repository at this point in the history
  • Loading branch information
4rthem committed Nov 13, 2024
1 parent d16a484 commit c3248b7
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 35 deletions.
2 changes: 1 addition & 1 deletion databox/api/src/Entity/Core/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ private function computePrivacyRoots(): array

public function getInheritedPrivacy(): ?int
{
return $this->getBestPrivacyInParentHierarchy();
return $this->parent?->getBestPrivacyInParentHierarchy();
}

public function getBestPrivacyInParentHierarchy(): int
Expand Down
64 changes: 31 additions & 33 deletions databox/client/src/components/Ui/PrivacyField.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {useState} from 'react';
import MenuItem from '@mui/material/MenuItem';
import {
Alert,
Checkbox,
FormControl,
FormControlLabel,
Expand Down Expand Up @@ -33,6 +34,10 @@ function getValue(value: string, workspace: boolean, auth: boolean): number {
}
}

function getAllowedValue(value: number, inheritedPrivacy?: number): number {
return Math.max(inheritedPrivacy ?? 0, value);
}

function getKeyValue(value: string): number {
switch (value) {
default:
Expand Down Expand Up @@ -83,67 +88,58 @@ export default function PrivacyField<TFieldValues extends FieldValues>({
defaultValue: 0 as any,
});

const firstValue = React.useMemo(() => value, []);
const [p, w, a] = getFields(value);
const [privacy, setPrivacy] = useState<string>(p);
const [workspaceOnly, setWorkspaceOnly] = useState(w);
const [auth, setAuth] = useState(a);

const ip = inheritedPrivacy ?? 0;
const inheritedKeyPrivacy = getKeyValue(getFields(ip)[0]);
const resolvedPrivacy =
inheritedKeyPrivacy > 0 && getKeyValue(privacy) <= inheritedKeyPrivacy
? getFields(inheritedKeyPrivacy)[0]
: privacy;
const workspaceOnlyLocked = getValue(resolvedPrivacy, false, true) === ip;
const resolvedWorkspaceOnly = workspaceOnlyLocked ? false : workspaceOnly;
const authLocked =
getValue(resolvedPrivacy, resolvedWorkspaceOnly, false) === ip;
const resolveAuth = authLocked ? false : auth;

React.useEffect(() => {
const [p, w, a] = getFields(value);
const [p, w, a] = getFields(getAllowedValue(value, inheritedPrivacy));
setPrivacy(p);
setWorkspaceOnly(
w ||
(firstValue === value &&
getKeyValue(privacy) < inheritedKeyPrivacy &&
getValue(resolvedPrivacy, true, resolveAuth) === ip)
);
setAuth(
a ||
(firstValue === value &&
getValue(resolvedPrivacy, resolvedWorkspaceOnly, true) ===
ip)
);
setWorkspaceOnly(w);
setAuth(a);
}, [value]);

const handlePChange = (e: SelectChangeEvent): void => {
const v = e.target.value;
setPrivacy(v);
onChange(getValue(v, resolvedWorkspaceOnly, resolveAuth));
onChange(getAllowedValue(getValue(v, workspaceOnly, auth), inheritedPrivacy));
};
const handleWSOnlyChange = (
e: React.ChangeEvent<HTMLInputElement>
): void => {
setWorkspaceOnly(e.target.checked);
onChange(getValue(resolvedPrivacy, e.target.checked, resolveAuth));
onChange(getAllowedValue(getValue(privacy, e.target.checked, auth), inheritedPrivacy));
};
const handleAuthChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
setAuth(e.target.checked);
onChange(
getValue(resolvedPrivacy, resolvedWorkspaceOnly, e.target.checked)
getAllowedValue(getValue(privacy, workspaceOnly, e.target.checked), inheritedPrivacy)
);
};

const workspaceOnlyLocked = !!inheritedPrivacy && getValue(privacy, true, auth) < inheritedPrivacy;
const authLocked = !!inheritedPrivacy && getValue(privacy, workspaceOnly, false) < inheritedPrivacy;

const label = t('form.privacy.label', 'Privacy');

return (
<>
{!!inheritedPrivacy ? <>
<Alert severity={'warning'}>
{t('form.privacy.inherited', 'This collection cannot be more restricted than its parent collection.')}
</Alert>
</> : null}
<FormControl>
<InputLabel>{label}</InputLabel>
<InputLabel>
{label}
</InputLabel>
<Select<string>
label={label}
value={resolvedPrivacy}
value={privacy}
onChange={handlePChange}
>
{Object.keys(choices).map(k => {
Expand All @@ -164,12 +160,13 @@ export default function PrivacyField<TFieldValues extends FieldValues>({
);
})}
</Select>
{['private', 'public'].includes(resolvedPrivacy) && (

{['private', 'public'].includes(privacy) && (
<FormControlLabel
disabled={workspaceOnlyLocked}
control={
<Checkbox
checked={resolvedWorkspaceOnly}
checked={workspaceOnly}
onChange={handleWSOnlyChange}
/>
}
Expand All @@ -180,12 +177,12 @@ export default function PrivacyField<TFieldValues extends FieldValues>({
labelPlacement="end"
/>
)}
{resolvedPrivacy === 'public' && (
{privacy === 'public' && (
<FormControlLabel
disabled={authLocked || resolvedWorkspaceOnly}
disabled={authLocked || workspaceOnly}
control={
<Checkbox
checked={resolveAuth || resolvedWorkspaceOnly}
checked={auth || workspaceOnly}
onChange={handleAuthChange}
/>
}
Expand All @@ -197,5 +194,6 @@ export default function PrivacyField<TFieldValues extends FieldValues>({
/>
)}
</FormControl>
</>
);
}
2 changes: 1 addition & 1 deletion databox/client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ export interface Collection extends IPermissions {
public: boolean;
shared: boolean;
privacy: number;
inheritedPrivacy: number;
inheritedPrivacy?: number;
createdAt: string;
updatedAt: string;
owner?: User;
Expand Down

0 comments on commit c3248b7

Please sign in to comment.