Skip to content

Commit

Permalink
Merge pull request #824 from syucream/fix/entityattr-acl
Browse files Browse the repository at this point in the history
Hide entry attribute if user isn't allowed to show it
  • Loading branch information
userlocalhost authored May 8, 2023
2 parents b681014 + 6ec97a5 commit e3e4ec9
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 4 deletions.
12 changes: 11 additions & 1 deletion entry/api_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class EntryAttributeType(TypedDict):
id: Optional[int]
type: int
is_mandatory: bool
is_readable: bool
value: EntryAttributeValue
schema: EntityAttributeType

Expand Down Expand Up @@ -142,6 +143,7 @@ class EntryAttributeTypeSerializer(serializers.Serializer):
id = serializers.IntegerField(allow_null=True)
type = serializers.IntegerField()
is_mandatory = serializers.BooleanField()
is_readable = serializers.BooleanField()
value = EntryAttributeValueSerializer()
schema = EntityAttributeTypeSerializer()

Expand Down Expand Up @@ -590,15 +592,23 @@ def get_default_attr_value(type: int) -> EntryAttributeValue:
.order_by("index")
)

user: User = self.context["request"].user

attrinfo: List[EntryAttributeType] = []
for entity_attr in entity_attrs:
attr = entity_attr.attr_list[0] if entity_attr.attr_list else None
value = get_attr_value(attr) if attr else get_default_attr_value(entity_attr.type)
is_readable = user.has_permission(entity_attr, ACLType.Readable)
value = (
get_attr_value(attr)
if attr and is_readable
else get_default_attr_value(entity_attr.type)
)
attrinfo.append(
{
"id": attr.id if attr else None,
"type": entity_attr.type,
"is_mandatory": entity_attr.is_mandatory,
"is_readable": is_readable,
"value": value,
"schema": {
"id": entity_attr.id,
Expand Down
58 changes: 58 additions & 0 deletions entry/tests/test_api_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def test_retrieve_entry(self):
"value": {"as_string": "hoge"},
"id": entry.attrs.get(schema__name="val").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="val").schema.id,
"name": "val",
Expand All @@ -151,6 +152,7 @@ def test_retrieve_entry(self):
},
"id": entry.attrs.get(schema__name="ref").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="ref").schema.id,
"name": "ref",
Expand All @@ -175,6 +177,7 @@ def test_retrieve_entry(self):
},
"id": entry.attrs.get(schema__name="name").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="name").schema.id,
"name": "name",
Expand All @@ -188,6 +191,7 @@ def test_retrieve_entry(self):
"value": {"as_boolean": False},
"id": entry.attrs.get(schema__name="bool").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="bool").schema.id,
"name": "bool",
Expand All @@ -201,6 +205,7 @@ def test_retrieve_entry(self):
"value": {"as_string": "2018-12-31"},
"id": entry.attrs.get(schema__name="date").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="date").schema.id,
"name": "date",
Expand All @@ -219,6 +224,7 @@ def test_retrieve_entry(self):
},
"id": entry.attrs.get(schema__name="group").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="group").schema.id,
"name": "group",
Expand All @@ -239,6 +245,7 @@ def test_retrieve_entry(self):
},
"id": entry.attrs.get(schema__name="groups").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="groups").schema.id,
"name": "groups",
Expand All @@ -257,6 +264,7 @@ def test_retrieve_entry(self):
},
"id": entry.attrs.get(schema__name="role").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="role").schema.id,
"name": "role",
Expand All @@ -277,6 +285,7 @@ def test_retrieve_entry(self):
},
"id": entry.attrs.get(schema__name="roles").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="roles").schema.id,
"name": "roles",
Expand All @@ -290,6 +299,7 @@ def test_retrieve_entry(self):
"value": {"as_string": "fuga"},
"id": entry.attrs.get(schema__name="text").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="text").schema.id,
"name": "text",
Expand All @@ -303,6 +313,7 @@ def test_retrieve_entry(self):
"value": {"as_array_string": ["foo", "bar"]},
"id": entry.attrs.get(schema__name="vals").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="vals").schema.id,
"name": "vals",
Expand All @@ -327,6 +338,7 @@ def test_retrieve_entry(self):
},
"id": entry.attrs.get(schema__name="refs").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="refs").schema.id,
"name": "refs",
Expand Down Expand Up @@ -363,6 +375,7 @@ def test_retrieve_entry(self):
},
"id": entry.attrs.get(schema__name="names").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="names").schema.id,
"name": "names",
Expand All @@ -376,6 +389,7 @@ def test_retrieve_entry(self):
"value": {"as_string": AttrTypeStr.DEFAULT_VALUE},
"id": None,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": self.entity.attrs.get(name="opt").id,
"name": "opt",
Expand Down Expand Up @@ -423,6 +437,46 @@ def test_retrieve_entry_without_permission(self):
resp = self.client.get("/entry/api/v2/%d/" % entry.id)
self.assertEqual(resp.status_code, 200)

# permission nothing entity attr
entity_attr = entry.attrs.get(schema__name="val").schema
entity_attr.is_public = False
entity_attr.save()
resp = self.client.get("/entry/api/v2/%d/" % entry.id)
self.assertEqual(resp.status_code, 200)
self.assertEqual(
next(filter(lambda x: x["schema"]["name"] == "val", resp.json()["attrs"])),
{
"type": AttrTypeValue["string"],
"value": {"as_string": ""},
"id": entry.attrs.get(schema__name="val").id,
"is_mandatory": False,
"is_readable": False,
"schema": {
"id": entry.attrs.get(schema__name="val").schema.id,
"name": "val",
},
},
)

# permission readable entity attr
entity_attr.readable.roles.add(self.role)
resp = self.client.get("/entry/api/v2/%d/" % entry.id)
self.assertEqual(resp.status_code, 200)
self.assertEqual(
next(filter(lambda x: x["schema"]["name"] == "val", resp.json()["attrs"])),
{
"type": AttrTypeValue["string"],
"value": {"as_string": ""},
"id": entry.attrs.get(schema__name="val").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="val").schema.id,
"name": "val",
},
},
)

def test_retrieve_entry_with_invalid_param(self):
resp = self.client.get("/entry/api/v2/%s/" % "hoge")
self.assertEqual(resp.status_code, 404)
Expand Down Expand Up @@ -516,6 +570,7 @@ def test_retrieve_entry_with_deleted_referrals(self):
},
"id": entry.attrs.get(schema__name="ref").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="ref").schema.id,
"name": "ref",
Expand All @@ -533,6 +588,7 @@ def test_retrieve_entry_with_deleted_referrals(self):
},
"id": entry.attrs.get(schema__name="name").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="name").schema.id,
"name": "name",
Expand All @@ -546,6 +602,7 @@ def test_retrieve_entry_with_deleted_referrals(self):
"value": {"as_array_object": []},
"id": entry.attrs.get(schema__name="refs").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="refs").schema.id,
"name": "refs",
Expand All @@ -568,6 +625,7 @@ def test_retrieve_entry_with_deleted_referrals(self):
},
"id": entry.attrs.get(schema__name="names").id,
"is_mandatory": False,
"is_readable": True,
"schema": {
"id": entry.attrs.get(schema__name="names").schema.id,
"name": "names",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ export interface EntryAttributeType {
* @memberof EntryAttributeType
*/
isMandatory: boolean;
/**
*
* @type {boolean}
* @memberof EntryAttributeType
*/
isReadable: boolean;
/**
*
* @type {EntryAttributeValue}
Expand Down Expand Up @@ -79,6 +85,7 @@ export function EntryAttributeTypeFromJSONTyped(
id: json["id"],
type: json["type"],
isMandatory: json["is_mandatory"],
isReadable: json["is_readable"],
value: EntryAttributeValueFromJSON(json["value"]),
schema: EntityAttributeTypeFromJSON(json["schema"]),
};
Expand All @@ -97,6 +104,7 @@ export function EntryAttributeTypeToJSON(
id: value.id,
type: value.type,
is_mandatory: value.isMandatory,
is_readable: value.isReadable,
value: EntryAttributeValueToJSON(value.value),
schema: EntityAttributeTypeToJSON(value.schema),
};
Expand Down
11 changes: 8 additions & 3 deletions frontend/src/components/entry/EntryAttributes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
TableCell,
TableRow,
Paper,
Typography,
} from "@mui/material";
import { styled } from "@mui/material/styles";
import React, { FC } from "react";
Expand Down Expand Up @@ -56,9 +57,13 @@ export const EntryAttributes: FC<Props> = ({ attributes }) => {
<StyledTableRow key={attr.schema.name}>
<AttrNameTableCell>{attr.schema.name}</AttrNameTableCell>
<AttrValueTableCell sx={{ p: "0px" }}>
<AttributeValue
attrInfo={{ type: attr.type, value: attr.value }}
/>
{attr.isReadable ? (
<AttributeValue
attrInfo={{ type: attr.type, value: attr.value }}
/>
) : (
<Typography>Permission denied.</Typography>
)}
</AttrValueTableCell>
</StyledTableRow>
))}
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/services/entry/Edit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ test("formalizeEntryInfo should return expect value", () => {
},
type: djangoContext?.attrTypeValue.string,
isMandatory: true,
isReadable: true,
value: {
asString: "",
},
Expand All @@ -176,6 +177,7 @@ test("formalizeEntryInfo should return expect value", () => {
},
type: djangoContext?.attrTypeValue.array_string,
isMandatory: false,
isReadable: true,
value: {
asArrayString: [],
},
Expand All @@ -190,6 +192,7 @@ test("formalizeEntryInfo should return expect value", () => {
},
type: djangoContext?.attrTypeValue.array_named_object,
isMandatory: true,
isReadable: true,
value: {
asArrayNamedObject: [],
},
Expand Down

0 comments on commit e3e4ec9

Please sign in to comment.