Skip to content

Commit f4709bf

Browse files
authored
Merge pull request #4094 from oat-sa/feat/ADF-1781/translations-feature
feat: add translation feature
2 parents 0ecf0fe + 314ef31 commit f4709bf

File tree

51 files changed

+4165
-28
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+4165
-28
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ Here you can find the environment variables including feature flags
106106
| DATA_STORE_STATISTIC_PUB_SUB_TOPIC | Topic name for statistic metadata Pub/Sub | - |
107107
| REDIRECT_AFTER_LOGOUT_URL | Allows to configure the redirect after logout via environment variable. The fallback is the configured redirect on urlroute.conf.php | - |
108108
| PORTAL_URL | The Portal url used on the back button of Portal theme | - |
109+
| FEATURE_TRANSLATION_ENABLED | Enable access to items/tests translations feature | - |
109110

110111

111112
# Routing

actions/class.Main.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,11 +521,13 @@ private function getSections($shownExtension, $shownStructure)
521521
$sections = [];
522522
$user = $this->getSession()->getUser();
523523
$structure = MenuService::getPerspective($shownExtension, $shownStructure);
524+
$sectionVisibilityFilter = $this->getSectionVisibilityFilter();
525+
524526
if (!is_null($structure)) {
525527
foreach ($structure->getChildren() as $section) {
526528
$resolver = new ActionResolver($section->getUrl());
527529

528-
if (!$this->getSectionVisibilityFilter()->isVisible($section->getId())) {
530+
if (!$sectionVisibilityFilter->isVisible($section->getId())) {
529531
continue;
530532
}
531533

@@ -540,6 +542,19 @@ private function getSections($shownExtension, $shownStructure)
540542

541543
if (FuncProxy::accessPossible($user, $resolver->getController(), $resolver->getAction())) {
542544
foreach ($section->getActions() as $action) {
545+
$sectionPath = $sectionVisibilityFilter->createSectionPath(
546+
[
547+
$section->getId(),
548+
$action->getId()
549+
]
550+
);
551+
552+
if (!$sectionVisibilityFilter->isVisible($sectionPath)) {
553+
$section->removeAction($action);
554+
555+
continue;
556+
}
557+
543558
$this->propagate($action);
544559
$resolver = new ActionResolver($action->getUrl());
545560
if (
@@ -580,7 +595,7 @@ protected function getUserService()
580595
return $this->getServiceLocator()->get(tao_models_classes_UserService::SERVICE_ID);
581596
}
582597

583-
private function getSectionVisibilityFilter(): SectionVisibilityFilterInterface
598+
private function getSectionVisibilityFilter(): SectionVisibilityFilter
584599
{
585600
if (empty($this->sectionVisibilityFilter)) {
586601
$this->sectionVisibilityFilter = $this->getServiceLocator()->get(SectionVisibilityFilter::SERVICE_ID);

actions/class.Translation.php

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
/**
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation; under version 2
7+
* of the License (non-upgradable).
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*
18+
* Copyright (c) 2024 (original work) Open Assessment Technologies SA;
19+
*/
20+
21+
declare(strict_types=1);
22+
23+
use oat\tao\model\http\HttpJsonResponseTrait;
24+
use oat\tao\model\Translation\Command\UpdateTranslationCommand;
25+
use oat\tao\model\Translation\Service\ResourceTranslationRetriever;
26+
use oat\tao\model\Translation\Service\ResourceTranslatableRetriever;
27+
use oat\tao\model\Translation\Service\TranslationCreationService;
28+
use oat\tao\model\Translation\Service\TranslationUpdateService;
29+
30+
class tao_actions_Translation extends tao_actions_CommonModule
31+
{
32+
use HttpJsonResponseTrait;
33+
34+
/**
35+
* @requiresRight id WRITE
36+
*/
37+
public function update(): void
38+
{
39+
try {
40+
$resource = $this->getTranslationUpdateService()->update(
41+
new UpdateTranslationCommand(
42+
$this->getRequestParameter('id'),
43+
$this->getRequestParameter('progress'),
44+
)
45+
);
46+
47+
$this->setSuccessJsonResponse(
48+
[
49+
'resourceUri' => $resource->getUri()
50+
]
51+
);
52+
} catch (Throwable $exception) {
53+
$this->setErrorJsonResponse($exception->getMessage());
54+
}
55+
}
56+
57+
/**
58+
* @requiresRight id WRITE
59+
*/
60+
public function translate(): void
61+
{
62+
try {
63+
$newResource = $this->getTranslationCreationService()->createByRequest($this->getPsrRequest());
64+
65+
$this->setSuccessJsonResponse(
66+
[
67+
'resourceUri' => $newResource->getUri()
68+
]
69+
);
70+
} catch (Throwable $exception) {
71+
$this->setErrorJsonResponse($exception->getMessage());
72+
}
73+
}
74+
75+
/**
76+
* @requiresRight id READ
77+
*/
78+
public function translations(): void
79+
{
80+
try {
81+
$this->setSuccessJsonResponse(
82+
$this->getResourceTranslationRetriever()->getByRequest($this->getPsrRequest())
83+
);
84+
} catch (Throwable $exception) {
85+
$this->setErrorJsonResponse($exception->getMessage());
86+
}
87+
}
88+
89+
/**
90+
* @requiresRight id READ
91+
*/
92+
public function translatable(): void
93+
{
94+
try {
95+
$this->setSuccessJsonResponse(
96+
$this->getResourceTranslatableRetriever()->getByRequest($this->getPsrRequest())
97+
);
98+
} catch (Throwable $exception) {
99+
$this->setErrorJsonResponse($exception->getMessage());
100+
}
101+
}
102+
103+
private function getResourceTranslationRetriever(): ResourceTranslationRetriever
104+
{
105+
return $this->getServiceManager()->getContainer()->get(ResourceTranslationRetriever::class);
106+
}
107+
108+
private function getResourceTranslatableRetriever(): ResourceTranslatableRetriever
109+
{
110+
return $this->getServiceManager()->getContainer()->get(ResourceTranslatableRetriever::class);
111+
}
112+
113+
private function getTranslationCreationService(): TranslationCreationService
114+
{
115+
return $this->getServiceManager()->getContainer()->get(TranslationCreationService::class);
116+
}
117+
118+
private function getTranslationUpdateService(): TranslationUpdateService
119+
{
120+
return $this->getServiceManager()->getContainer()->get(TranslationUpdateService::class);
121+
}
122+
}

doc/taoApi.yml

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,89 @@ info:
55
version: v1
66

77
paths:
8+
/tao/Translation/update:
9+
post:
10+
summary: Return a list of translations for a given translatable resource
11+
requestBody:
12+
required: true
13+
content:
14+
multipart/form-data:
15+
schema:
16+
type: object
17+
properties:
18+
id:
19+
type: string
20+
description: The resource URI
21+
progress:
22+
type: string
23+
description: The progress URI
24+
responses:
25+
200:
26+
$ref: '#/components/responses/TranslateResponse'
27+
400:
28+
$ref: '#/components/responses/BadRequestResponse'
29+
500:
30+
$ref: '#/components/responses/InternalServerErrorResponse'
31+
/tao/Translation/translations:
32+
get:
33+
summary: Return a list of translations for a given translatable resource
34+
parameters:
35+
- in: query
36+
name: id
37+
required: true
38+
schema:
39+
type: string
40+
description: The RDF resource id
41+
- in: query
42+
name: languageUri
43+
required: false
44+
schema:
45+
type: string
46+
description: The RDF language URI
47+
responses:
48+
200:
49+
$ref: '#/components/responses/TranslationsResponse'
50+
400:
51+
$ref: '#/components/responses/BadRequestResponse'
52+
500:
53+
$ref: '#/components/responses/InternalServerErrorResponse'
54+
/tao/Translation/translatable:
55+
get:
56+
summary: Return translatable resources
57+
parameters:
58+
- in: query
59+
name: id
60+
required: true
61+
schema:
62+
type: string
63+
description: The RDF resource id
64+
responses:
65+
200:
66+
$ref: '#/components/responses/TranslatableResponse'
67+
400:
68+
$ref: '#/components/responses/BadRequestResponse'
69+
500:
70+
$ref: '#/components/responses/InternalServerErrorResponse'
71+
/tao/Translation/translate:
72+
post:
73+
summary: translate a resources
74+
requestBody:
75+
required: true
76+
content:
77+
multipart/form-data:
78+
schema:
79+
type: object
80+
properties:
81+
id:
82+
type: string
83+
description: The resource URI
84+
responses:
85+
200:
86+
$ref: '#/components/responses/TranslateResponse'
87+
400:
88+
$ref: '#/components/responses/BadRequestResponse'
89+
500:
90+
$ref: '#/components/responses/InternalServerErrorResponse'
891
/tao/Languages/index:
992
get:
1093
summary: Get a list of available languages in the TAO platform
@@ -46,6 +129,70 @@ paths:
46129
$ref: '#/components/responses/InternalServerErrorResponse'
47130
components:
48131
schemas:
132+
Translations:
133+
properties:
134+
success:
135+
type: boolean
136+
example: true
137+
data:
138+
type: object
139+
properties:
140+
resources:
141+
type: array
142+
items:
143+
properties:
144+
originResourceUri:
145+
type: string
146+
resourceUri:
147+
type: string
148+
resourceLabel:
149+
type: string
150+
metadata:
151+
type: object
152+
properties:
153+
key:
154+
type: object
155+
properties:
156+
value:
157+
type: string
158+
literal:
159+
type: string
160+
Translatable:
161+
properties:
162+
success:
163+
type: boolean
164+
example: true
165+
data:
166+
type: object
167+
properties:
168+
resources:
169+
type: array
170+
items:
171+
properties:
172+
resourceUri:
173+
type: string
174+
resourceLabel:
175+
type: string
176+
metadata:
177+
type: object
178+
properties:
179+
key:
180+
type: object
181+
properties:
182+
value:
183+
type: string
184+
literal:
185+
type: string
186+
Translated:
187+
properties:
188+
success:
189+
type: boolean
190+
example: true
191+
data:
192+
type: object
193+
properties:
194+
resourceUri:
195+
type: string
49196
ResourceRelationResource:
50197
description: 'A resource related to another resources'
51198
type: object
@@ -104,6 +251,24 @@ components:
104251
message:
105252
type: string
106253
responses:
254+
TranslationsResponse:
255+
description: The list of translations
256+
content:
257+
application/json:
258+
schema:
259+
$ref: '#/components/schemas/Translations'
260+
TranslatableResponse:
261+
description: The list of translatable
262+
content:
263+
application/json:
264+
schema:
265+
$ref: '#/components/schemas/Translatable'
266+
TranslateResponse:
267+
description: The resource is translated
268+
content:
269+
application/json:
270+
schema:
271+
$ref: '#/components/schemas/Translated'
107272
ResourceRelationsResponse:
108273
description: Bad request
109274
content:

0 commit comments

Comments
 (0)