Skip to content

Commit

Permalink
Making available extension listed in the instance structure (view).
Browse files Browse the repository at this point in the history
  • Loading branch information
krulis-martin committed Dec 21, 2024
1 parent 3c490a5 commit d8db9da
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 30 deletions.
26 changes: 16 additions & 10 deletions app/V1Module/presenters/InstancesPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
*/
class InstancesPresenter extends BasePresenter
{

/**
* @var Instances
* @inject
Expand Down Expand Up @@ -94,7 +93,9 @@ function (Instance $instance) {
return $instance->isAllowed();
}
);
$this->sendSuccessResponse($this->instanceViewFactory->getInstances($instances));
$this->sendSuccessResponse(
$this->instanceViewFactory->getInstances($instances, $this->getCurrentUserOrNull())

Check failure on line 97 in app/V1Module/presenters/InstancesPresenter.php

View workflow job for this annotation

GitHub Actions / phpstan (8.2)

Call to an undefined method App\V1Module\Presenters\InstancesPresenter::getCurrentUserOrNull().

Check failure on line 97 in app/V1Module/presenters/InstancesPresenter.php

View workflow job for this annotation

GitHub Actions / phpstan (8.3)

Call to an undefined method App\V1Module\Presenters\InstancesPresenter::getCurrentUserOrNull().
);
}

public function checkCreateInstance()
Expand All @@ -109,7 +110,8 @@ public function checkCreateInstance()
* @POST
* @Param(type="post", name="name", validation="string:2..", description="Name of the instance")
* @Param(type="post", name="description", required=false, description="Description of the instance")
* @Param(type="post", name="isOpen", validation="bool", description="Should the instance be open for registration?")
* @Param(type="post", name="isOpen", validation="bool",
* description="Should the instance be open for registration?")
* @throws ForbiddenRequestException
*/
public function actionCreateInstance()
Expand All @@ -129,7 +131,7 @@ public function actionCreateInstance()
$this->instances->persist($instance->getRootGroup(), false);
$this->instances->persist($localizedRootGroup, false);
$this->instances->persist($instance);
$this->sendSuccessResponse($this->instanceViewFactory->getInstance($instance), IResponse::S201_CREATED);
$this->sendSuccessResponse($this->instanceViewFactory->getInstance($instance, $user), IResponse::S201_CREATED);
}

public function checkUpdateInstance(string $id)
Expand All @@ -144,7 +146,8 @@ public function checkUpdateInstance(string $id)
/**
* Update an instance
* @POST
* @Param(type="post", name="isOpen", validation="bool", required=false, description="Should the instance be open for registration?")
* @Param(type="post", name="isOpen", validation="bool", required=false,
* description="Should the instance be open for registration?")
* @param string $id An identifier of the updated instance
*/
public function actionUpdateInstance(string $id)
Expand All @@ -159,7 +162,7 @@ public function actionUpdateInstance(string $id)

$instance->setIsOpen($isOpen);
$this->instances->persist($instance);
$this->sendSuccessResponse($this->instanceViewFactory->getInstance($instance));
$this->sendSuccessResponse($this->instanceViewFactory->getInstance($instance, $this->getCurrentUser()));
}

public function checkDeleteInstance(string $id)
Expand Down Expand Up @@ -208,7 +211,7 @@ public function checkDetail(string $id)
public function actionDetail(string $id)
{
$instance = $this->instances->findOrThrow($id);
$this->sendSuccessResponse($this->instanceViewFactory->getInstance($instance));
$this->sendSuccessResponse($this->instanceViewFactory->getInstance($instance, $this->getCurrentUser()));
}

public function checkLicences(string $id)
Expand Down Expand Up @@ -268,9 +271,12 @@ public function checkUpdateLicence(string $licenceId)
/**
* Update an existing license for an instance
* @POST
* @Param(type="post", name="note", validation="string:2..255", required=false, description="A note for users or administrators")
* @Param(type="post", name="validUntil", validation="string", required=false, description="Expiration date of the license")
* @Param(type="post", name="isValid", validation="bool", required=false, description="Administrator switch to toggle licence validity")
* @Param(type="post", name="note", validation="string:2..255", required=false,
* description="A note for users or administrators")
* @Param(type="post", name="validUntil", validation="string", required=false,
* description="Expiration date of the license")
* @Param(type="post", name="isValid", validation="bool", required=false,
* description="Administrator switch to toggle licence validity")
* @param string $licenceId Identifier of the licence
* @throws NotFoundException
*/
Expand Down
5 changes: 4 additions & 1 deletion app/V1Module/presenters/UsersPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,10 @@ public function actionInstances(string $id)
{
$user = $this->users->findOrThrow($id);

$this->sendSuccessResponse($this->instanceViewFactory->getInstances($user->getInstances()->toArray()));
$this->sendSuccessResponse($this->instanceViewFactory->getInstances(
$user->getInstances()->toArray(),
$this->getCurrentUser()
));
}

public function checkSetRole(string $id)
Expand Down
1 change: 0 additions & 1 deletion app/commands/PlagiarismDetectionAccessToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace App\Console;

use App\Model\Entity\User;
use App\Model\Repository\Users;
use App\Security\AccessManager;
use App\Security\TokenScope;
Expand Down
2 changes: 1 addition & 1 deletion app/config/config.local.neon.example
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ parameters:
en: "English Caption"
url: "https://extetrnal.domain.com/recodex/extension?token={token}&locale={locale}" # '{token}' and '{locale}' are placeholders
token: # generated from tmp tokens passed via URL so the ext. tool can access ReCodEx API
scope: master # scope of generated tokens (to be used by the extension)
scopes: [ 'master', 'refresh' ] # list of scopes for generated tokens (to be used by the extension)
user: null # user override (ID) for generating tokens (if null, the token will be generated for logged-in user)
instances: [] # array of instances where this extension is enabled (empty array = all)
user: # filters applied to determine, whether logged-in user can access the extension
Expand Down
27 changes: 19 additions & 8 deletions app/helpers/Extensions/ExtensionConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Model\Entity\Instance;
use App\Model\Entity\User;
use App\Exceptions\ConfigException;
use App\Security\TokenScope;
use Nette;
use Nette\Utils\Arrays;

Expand Down Expand Up @@ -34,9 +35,10 @@ class ExtensionConfig
private string $url;

/**
* A scope that will be set to (full) access tokens generated after tmp-token verification.
* List of scopes that will be set to (full) access tokens generated after tmp-token verification.
* @var string[]
*/
private string $tokenScope;
private array $tokenScopes;

Check failure on line 41 in app/helpers/Extensions/ExtensionConfig.php

View workflow job for this annotation

GitHub Actions / phpstan (8.2)

Property App\Helpers\ExtensionConfig::$tokenScopes is never read, only written.

Check failure on line 41 in app/helpers/Extensions/ExtensionConfig.php

View workflow job for this annotation

GitHub Actions / phpstan (8.3)

Property App\Helpers\ExtensionConfig::$tokenScopes is never read, only written.

/**
* User override for (full) access tokens. This user will be used instead of user ID passed in tmp token.
Expand Down Expand Up @@ -79,11 +81,15 @@ public function __construct(array $config)
}

$this->url = Arrays::get($config, "url");
$this->tokenScope = Arrays::get($config, ["token", "scope"], "master");
$this->tokenScopes = Arrays::get(
$config,
["token", "scopes"],
[ TokenScope::MASTER, TokenScope::REFRESH ]
) ?? [];
$this->tokenUserId = Arrays::get($config, ["token", "user"], null);
$this->instances = Arrays::get($config, "instances", []);
$this->userRoles = Arrays::get($config, ["user", "roles"], []);
$this->userExternalLogins = Arrays::get($config, ["user", "externalLogins"], []);
$this->instances = Arrays::get($config, "instances", []) ?? [];
$this->userRoles = Arrays::get($config, ["user", "roles"], []) ?? [];
$this->userExternalLogins = Arrays::get($config, ["user", "externalLogins"], []) ?? [];
}

public function getId(): string
Expand Down Expand Up @@ -113,15 +119,20 @@ public function getUrl(string $token, string $locale): string
/**
* Check whether this extension is accessible by given user in given instance.
* @param Instance $instance
* @param User $user
* @param User|null $user (if null, the extension must be accessible by all users)
* @return bool true if the extension is accessible
*/
public function isAccessible(Instance $instance, User $user): bool
public function isAccessible(Instance $instance, ?User $user): bool
{
if ($this->instances && !in_array($instance->getId(), $this->instances)) {
return false;
}

if (!$user) {
// test accessibility for all users (no user filters must be present)
return !$this->userRoles && !$this->userExternalLogins;
}

if ($this->userRoles && !in_array($user->getRole(), $this->userRoles)) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions app/helpers/Extensions/Extensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ public function getExtension(string $id): ?ExtensionConfig
/**
* Filter out extensions that are accessible by given user in given instance.
* @param Instance $instance
* @param User $user
* @param User|null $user (if null, only extensions available to all users are listed)
* @return ExtensionConfig[] array indexed by extension IDs
*/
public function getAccessibleExtensions(Instance $instance, User $user): array
public function getAccessibleExtensions(Instance $instance, ?User $user): array
{
$res = [];
foreach ($this->extensions as $id => $extension) {
Expand Down
27 changes: 20 additions & 7 deletions app/model/view/InstanceViewFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

namespace App\Model\View;

use App\Helpers\Localizations;
use App\Model\Entity\Instance;
use App\Model\Entity\LocalizedGroup;
use App\Model\Entity\User;
use App\Helpers\Localizations;
use App\Helpers\Extensions;

/**
* Factory for instance views which somehow do not fit into json serialization
Expand All @@ -15,21 +17,30 @@ class InstanceViewFactory
/** @var GroupViewFactory */
private $groupViewFactory;

public function __construct(GroupViewFactory $groupViewFactory)
/** @var Extensions */
private $extensions;

public function __construct(GroupViewFactory $groupViewFactory, Extensions $extensions)
{
$this->groupViewFactory = $groupViewFactory;
$this->extensions = $extensions;
}


/**
* Get as much instance detail info as your permissions grants you.
* @param Instance $instance
* @param User|null $loggedUser (to better target available extensions)
* @return array
*/
public function getInstance(Instance $instance): array
public function getInstance(Instance $instance, ?User $loggedUser = null): array
{
/** @var LocalizedGroup|null $localizedRootGroup */
$localizedRootGroup = Localizations::getPrimaryLocalization($instance->getRootGroup()->getLocalizedTexts());
$extensions = [];
foreach ($this->extensions->getAccessibleExtensions($instance, $loggedUser) as $ext) {
$extensions[$ext->getId()] = $ext->getCaption();
}

return [
"id" => $instance->getId(),
Expand All @@ -43,21 +54,23 @@ public function getInstance(Instance $instance): array
"deletedAt" => $instance->getDeletedAt() ? $instance->getDeletedAt()->getTimestamp() : null,
"adminId" => $instance->getAdmin() ? $instance->getAdmin()->getId() : null,
"rootGroup" => $this->groupViewFactory->getGroup($instance->getRootGroup()),
"rootGroupId" => $instance->getRootGroup()->getId()
"rootGroupId" => $instance->getRootGroup()->getId(),
"extensions" => $extensions,
];
}

/**
* Get instance data.
* @param Instance[] $instances
* @param User|null $loggedUser (to better target available extensions)
* @return array
*/
public function getInstances(array $instances): array
public function getInstances(array $instances, ?User $loggedUser = null): array
{
$instances = array_values($instances);
return array_map(
function (Instance $instance) {
return $this->getInstance($instance);
function (Instance $instance) use ($loggedUser) {
return $this->getInstance($instance, $loggedUser);
},
$instances
);
Expand Down

0 comments on commit d8db9da

Please sign in to comment.