Skip to content

Commit 30d4f6c

Browse files
authored
Merge branch 'master' into PS-890-store-user-pref
2 parents fe6d2b0 + bf74909 commit 30d4f6c

28 files changed

+353
-358
lines changed

databox/api/fixtures/Newspaper.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,11 +505,14 @@ App\Entity\Integration\WorkspaceIntegration:
505505
title: ToastUI
506506
integration: tui.photo-editor
507507
workspace: '@w_newspaper'
508+
ownerId: <keycloakUser("phrasea-admin", ["phrasea-admin"])>
508509
wi_renditions:
509510
integration: core.rendition
510511
workspace: '@w_newspaper'
512+
ownerId: <keycloakUser("phrasea-admin", ["phrasea-admin"])>
511513
wi_watermark:
512514
integration: core.watermark
515+
ownerId: <keycloakUser("phrasea-admin", ["phrasea-admin"])>
513516
workspace: '@w_newspaper'
514517
config:
515518
attributeName: watermark
@@ -518,13 +521,15 @@ App\Entity\Integration\WorkspaceIntegration:
518521
needs:
519522
- '@wi_renditions'
520523
wi_blurhash:
524+
ownerId: <keycloakUser("phrasea-admin", ["phrasea-admin"])>
521525
integration: blurhash
522526
workspace: '@w_newspaper'
523527
config:
524528
rendition: thumbnail
525529
needs:
526530
- '@wi_renditions'
527531
wi_expose:
532+
ownerId: <keycloakUser("phrasea-admin", ["phrasea-admin"])>
528533
title: Expose Basket
529534
integration: phrasea.expose
530535
config:

databox/api/src/Api/Model/Input/Attribute/AbstractExtendedAttributeInput.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace App\Api\Model\Input\Attribute;
66

7+
use App\Entity\Traits\AssetAnnotationsInterface;
8+
use Symfony\Component\Validator\Constraints as Assert;
9+
710
abstract class AbstractExtendedAttributeInput extends AbstractBaseAttributeInput
811
{
912
/**
@@ -22,6 +25,12 @@ abstract class AbstractExtendedAttributeInput extends AbstractBaseAttributeInput
2225
/**
2326
* @var array
2427
*/
28+
#[Assert\Collection(
29+
fields: [
30+
'type' => new Assert\Choice(AssetAnnotationsInterface::TYPES),
31+
],
32+
allowExtraFields: true,
33+
)]
2534
public $annotations;
2635

2736
/**

databox/api/src/Api/Model/Output/AttributeDefinitionOutput.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class AttributeDefinitionOutput extends AbstractUuidOutput
4848
#[Groups([AttributeDefinition::GROUP_LIST])]
4949
public ?string $fileType = null;
5050

51-
#[Groups([AttributeDefinition::GROUP_LIST, Asset::GROUP_LIST, Share::GROUP_PUBLIC_READ])]
51+
#[Groups([AttributeDefinition::GROUP_LIST, Asset::GROUP_LIST, Asset::GROUP_READ, Share::GROUP_PUBLIC_READ])]
5252
public string $fieldType = TextAttributeType::NAME;
5353

5454
#[Groups([AttributeDefinition::GROUP_LIST])]

databox/api/src/Attribute/BatchAttributeManager.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ public function handleBatch(
204204
'ids' => $action->ids,
205205
'origin' => $action->origin,
206206
'originVendor' => $action->originVendor,
207+
'originVendorContext' => $action->originVendorContext,
207208
]);
208209
break;
209210
case self::ACTION_SET:
@@ -469,6 +470,11 @@ private function deleteAttributes(
469470
->andWhere('a.originVendor = :originVendor')
470471
->setParameter('originVendor', $options['originVendor']);
471472
}
473+
if ($options['originVendorContext'] ?? null) {
474+
$qb
475+
->andWhere('a.originVendorContext = :ovc')
476+
->setParameter('ovc', $options['originVendorContext']);
477+
}
472478
$qb->getQuery()->execute();
473479
}
474480

databox/api/src/Entity/Core/AttributeDefinition.php

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,17 @@
4343
shortName: 'attribute-definition',
4444
operations: [
4545
new Get(
46-
security: 'is_granted("'.AbstractVoter::READ.'", object)'
46+
security: 'is_granted("'.AbstractVoter::READ.'", object)',
4747
),
4848
new Delete(security: 'is_granted("DELETE", object)'),
4949
new Put(
50-
normalizationContext: [
51-
'groups' => [self::GROUP_READ],
52-
],
5350
security: 'is_granted("'.AbstractVoter::EDIT.'", object)'
5451
),
5552
new Patch(security: 'is_granted("'.AbstractVoter::EDIT.'", object)'),
5653
new GetCollection(
54+
normalizationContext: [
55+
'groups' => [AttributeDefinition::GROUP_LIST],
56+
],
5757
parameters: [
5858
'searchable' => new QueryParameter(
5959
schema: ['type' => 'boolean'],
@@ -62,12 +62,9 @@
6262
'workspaceId' => new QueryParameter(
6363
schema: ['type' => 'string'],
6464
),
65-
]
65+
],
6666
),
6767
new Post(
68-
normalizationContext: [
69-
'groups' => [self::GROUP_READ],
70-
],
7168
security: 'is_granted("'.JwtUser::IS_AUTHENTICATED_FULLY.'")',
7269
securityPostDenormalize: 'is_granted("CREATE", object)',
7370
),
@@ -96,7 +93,7 @@
9693
),
9794
],
9895
normalizationContext: [
99-
'groups' => [AttributeDefinition::GROUP_LIST],
96+
'groups' => [AttributeDefinition::GROUP_LIST, AttributeDefinition::GROUP_READ],
10097
],
10198
input: AttributeDefinitionInput::class,
10299
output: AttributeDefinitionOutput::class,

databox/api/src/Entity/Core/RenditionPolicy.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class RenditionPolicy extends AbstractUuidEntity implements \Stringable
6363
#[Assert\NotNull]
6464
protected ?Workspace $workspace = null;
6565

66-
#[Groups([RenditionPolicy::GROUP_LIST, RenditionPolicy::GROUP_READ])]
66+
#[Groups([RenditionPolicy::GROUP_LIST, RenditionPolicy::GROUP_READ, RenditionDefinition::GROUP_LIST, RenditionDefinition::GROUP_READ])]
6767
#[ORM\Column(type: Types::STRING, length: 80)]
6868
#[Assert\NotNull]
6969
private ?string $name = null;

databox/api/src/Entity/Traits/AssetAnnotationsInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface AssetAnnotationsInterface
1010
// "x", "y", "r" (radius in %), "c"? (border color in hexa), "f"? (fill color in hexa)
1111
final public const string TYPE_CIRCLE = 'circle';
1212

13-
// "x1", "y1", "x2", "y2", "c"? (border color in hexa), "f"? (fill color in hexa)
13+
// "x", "y", "w", "h", "c"? (border color in hexa), "f"? (fill color in hexa)
1414
final public const string TYPE_RECTANGLE = 'rect';
1515

1616
// "t" (time: float in seconds)

databox/api/src/Integration/Aws/Rekognition/RekognitionAnalyzer.php

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use App\Entity\Core\Asset;
1313
use App\Entity\Core\Attribute;
1414
use App\Entity\Core\File;
15+
use App\Entity\Traits\AssetAnnotationsInterface;
1516
use App\Integration\ApiBudgetLimiter;
1617
use App\Integration\IntegrationConfig;
1718
use App\Integration\IntegrationDataManager;
@@ -51,22 +52,40 @@ public function analyze(?Asset $asset, File $file, string $category, Integration
5152

5253
if (!empty($result) && $asset instanceof Asset) {
5354
if (AwsRekognitionIntegration::LABELS === $category && !empty($config['labels']['attributes'] ?? [])) {
54-
$this->saveTextsToAttributes($asset, array_map(fn (array $text): array => [
55+
$this->saveTextsToAttributes($category, $asset, array_map(fn (array $text): array => [
5556
'value' => $text['Name'],
56-
'confidence' => $text['Confidence'],
57+
'confidence' => $text['Confidence'] / 100,
58+
'annotations' => array_map(fn (array $instance): array => [
59+
'type' => AssetAnnotationsInterface::TYPE_RECTANGLE,
60+
'x' => $instance['BoundingBox']['Left'] ?? null,
61+
'y' => $instance['BoundingBox']['Top'] ?? null,
62+
'w' => $instance['BoundingBox']['Width'] ?? null,
63+
'h' => $instance['BoundingBox']['Height'] ?? null,
64+
], $text['Instances'] ?? []),
5765
], $result['Labels']), $config['labels']['attributes']);
5866
} elseif (AwsRekognitionIntegration::TEXTS === $category && !empty($config['texts']['attributes'] ?? [])) {
59-
$this->saveTextsToAttributes($asset, array_map(fn (array $text): array => [
60-
'value' => $text['DetectedText'],
61-
'confidence' => $text['Confidence'],
62-
], array_filter($result['TextDetections'], fn (array $text): bool => 'LINE' === $text['Type'])), $config['texts']['attributes']);
67+
$this->saveTextsToAttributes($category, $asset, array_map(function (array $text): array {
68+
$box = $text['Geometry']['BoundingBox'] ?? [];
69+
70+
return [
71+
'value' => $text['DetectedText'],
72+
'confidence' => $text['Confidence'] / 100,
73+
'annotations' => [[
74+
'type' => AssetAnnotationsInterface::TYPE_RECTANGLE,
75+
'x' => $box['Left'] ?? null,
76+
'y' => $box['Top'] ?? null,
77+
'w' => $box['Width'] ?? null,
78+
'h' => $box['Height'] ?? null,
79+
]],
80+
];
81+
}, array_filter($result['TextDetections'], fn (array $text): bool => 'LINE' === $text['Type'])), $config['texts']['attributes']);
6382
}
6483
}
6584

6685
return $result;
6786
}
6887

69-
protected function saveTextsToAttributes(Asset $asset, array $texts, array $attributes): void
88+
protected function saveTextsToAttributes(string $category, Asset $asset, array $texts, array $attributes): void
7089
{
7190
foreach ($attributes as $attrConfig) {
7291
$attrDef = $this->attributeManager
@@ -84,17 +103,20 @@ protected function saveTextsToAttributes(Asset $asset, array $texts, array $attr
84103
$i->action = BatchAttributeManager::ACTION_DELETE;
85104
$i->origin = Attribute::ORIGIN_MACHINE;
86105
$i->originVendor = AwsRekognitionIntegration::getName();
106+
$i->originVendorContext = $category;
87107
$input->actions[] = $i;
88108

89109
foreach ($texts as $text) {
90-
if (null === $threshold || $threshold < $text['confidence']) {
110+
if (null === $threshold || $text['confidence'] >= $threshold) {
91111
$i = new AttributeActionInput();
92112
$i->action = BatchAttributeManager::ACTION_ADD;
93113
$i->originVendor = AwsRekognitionIntegration::getName();
114+
$i->originVendorContext = $category;
94115
$i->origin = Attribute::ORIGIN_MACHINE;
95116
$i->definitionId = $attrDef->getId();
96117
$i->confidence = $text['confidence'];
97118
$i->value = $text['value'];
119+
$i->annotations = $text['annotations'] ?? [];
98120
$input->actions[] = $i;
99121
}
100122
}

databox/client/src/components/Basket/BasketsPanel.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,19 @@ function BasketsPanel({selected}: Props) {
159159
contextMenu={contextMenu}
160160
id={'basket-context-menu'}
161161
>
162-
<MenuItem onClick={() => onEdit(contextMenu.data)}>
162+
<MenuItem
163+
disabled={!contextMenu.data.capabilities.canEdit}
164+
onClick={() => onEdit(contextMenu.data)}
165+
>
163166
<ListItemIcon>
164167
<EditIcon />
165168
</ListItemIcon>
166169
{t('basket.actions.edit', 'Edit Basket')}
167170
</MenuItem>
168-
<MenuItem onClick={() => onDelete(contextMenu.data)}>
171+
<MenuItem
172+
disabled={!contextMenu.data.capabilities.canDelete}
173+
onClick={() => onDelete(contextMenu.data)}
174+
>
169175
<ListItemIcon>
170176
<DeleteIcon />
171177
</ListItemIcon>

databox/client/src/components/Dialog/Workspace/AttributeDefinitionManager.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,12 @@ export default function AttributeDefinitionManager({
443443
function normalizeData(data: AttributeDefinition) {
444444
return {
445445
...data,
446-
policy: data.policy ? (data.policy as AttributePolicy)['@id'] : null,
446+
policy:
447+
typeof data.policy === 'string'
448+
? data.policy
449+
: data.policy
450+
? (data.policy as AttributePolicy)['@id']
451+
: null,
447452
entityList: data.entityList
448453
? (data.entityList as EntityList)['@id']
449454
: null,

0 commit comments

Comments
 (0)