Skip to content

Commit

Permalink
Merge pull request #136 from oat-sa/feature/TR-4685/nrps-membership-d…
Browse files Browse the repository at this point in the history
…ifference

Feature TR-4685 NRPS membership difference
  • Loading branch information
wazelin authored Dec 9, 2022
2 parents 3dc295d + b3ac9ff commit b6a4abe
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 85 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
CHANGELOG
=========

2.5.0
-----

* Added rel="differences" link to the NRPS membership service
* Added time-based membership differences exposure to the NRPS membership service
* Added members' soft delete

2.4.7
-----

Expand Down
2 changes: 1 addition & 1 deletion config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ parameters:
application_env: '%env(resolve:APP_ENV)%'
application_api_key: '%env(resolve:APP_API_KEY)%'
application_vendors: '%kernel.project_dir%/vendor/composer/installed.php'
application_version: '2.4.7'
application_version: '2.5.0'
container.dumper.inline_factories: true
cache.redis.namespace: '%env(default:cache.redis.namespace.default:REDIS_CACHE_NAMESPACE)%'
cache.redis.namespace.default: 'devkit'
Expand Down
31 changes: 8 additions & 23 deletions src/Action/Api/Platform/Nrps/UpdateMembershipAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@

use App\Action\Api\ApiActionInterface;
use App\Generator\UrlGenerator;
use App\Nrps\MembershipRepository;
use OAT\Library\Lti1p3Nrps\Factory\Member\MemberFactoryInterface;
use OAT\Library\Lti1p3Nrps\Model\Member\MemberCollection;
use App\Nrps\MembershipService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand All @@ -36,22 +34,17 @@

class UpdateMembershipAction implements ApiActionInterface
{
/** @var MemberFactoryInterface */
private $factory;

/** @var MembershipRepository */
private $repository;
/** @var MembershipService */
private $service;

/** @var UrlGenerator */
private $generator;

public function __construct(
MemberFactoryInterface $factory,
MembershipRepository $repository,
MembershipService $service,
UrlGenerator $generator
) {
$this->factory = $factory;
$this->repository = $repository;
$this->service = $service;
$this->generator = $generator;
}

Expand All @@ -66,7 +59,7 @@ public function __invoke(Request $request, string $membershipIdentifier): Respon
throw new AccessDeniedHttpException('the membership with identifier default cannot be updated');
}

$membership = $this->repository->find($membershipIdentifier);
$membership = $this->service->findMembership($membershipIdentifier);

if (null === $membership) {
throw new NotFoundHttpException(
Expand All @@ -90,18 +83,10 @@ public function __invoke(Request $request, string $membershipIdentifier): Respon

$membership->setContext($context);

if(array_key_exists('members', $data)) {
$memberCollection = new MemberCollection();

foreach ($data['members'] as $member) {
$memberCollection->add($this->factory->create($member));
}

$membership->setMembers($memberCollection);
if (array_key_exists('members', $data)) {
$this->service->updateMembership($membership, $data['members']);
}

$this->repository->save($membership);

return new JsonResponse(
[
'membership' => $membership,
Expand Down
41 changes: 19 additions & 22 deletions src/Action/Platform/Nrps/EditMembershipAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
namespace App\Action\Platform\Nrps;

use App\Form\Platform\Nrps\MembershipType;
use App\Nrps\MembershipRepository;
use App\Nrps\MembershipService;
use OAT\Library\Lti1p3Nrps\Factory\Member\MemberFactoryInterface;
use OAT\Library\Lti1p3Nrps\Model\Context\Context;
use OAT\Library\Lti1p3Nrps\Model\Member\MemberCollection;
use OAT\Library\Lti1p3Nrps\Model\Member\MemberInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -42,8 +42,8 @@ class EditMembershipAction
/** @var FlashBagInterface */
private $flashBag;

/** @var MembershipRepository */
private $repository;
/** @var MembershipService */
private $service;

/** @var Environment */
private $twig;
Expand All @@ -54,28 +54,24 @@ class EditMembershipAction
/** @var RouterInterface */
private $router;

/** @var MemberFactoryInterface */
private $memberFactory;

public function __construct(
FlashBagInterface $flashBag,
MembershipRepository $repository,
MembershipService $service,
Environment $twig,
FormFactoryInterface $factory,
RouterInterface $router,
MemberFactoryInterface $memberFactory
) {
$this->flashBag = $flashBag;
$this->repository = $repository;
$this->service = $service;
$this->twig = $twig;
$this->factory = $factory;
$this->router = $router;
$this->memberFactory = $memberFactory;
}

public function __invoke(Request $request, string $membershipIdentifier): Response
{
$membership = $this->repository->find($membershipIdentifier);
$membership = $this->service->findMembership($membershipIdentifier);

if (null === $membership) {
throw new NotFoundHttpException(
Expand All @@ -84,7 +80,16 @@ public function __invoke(Request $request, string $membershipIdentifier): Respon
}

if ($membership->getMembers()->count() !== 0) {
$members = json_encode($membership->getMembers());
$members = json_encode(
array_values(
array_filter(
$membership->getMembers()->all(),
static function (MemberInterface $member) {
return $member->getStatus() !== MemberInterface::STATUS_DELETED;
}
)
)
);
} else {
$members = '';
}
Expand All @@ -106,7 +111,6 @@ public function __invoke(Request $request, string $membershipIdentifier): Respon
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {

$formData = $form->getData();

$membership->setContext(
Expand All @@ -117,23 +121,16 @@ public function __invoke(Request $request, string $membershipIdentifier): Respon
)
);

$memberCollection = new MemberCollection();

$members = [];
if ($formData['members']) {
$members = json_decode($formData['members'], true);

if (JSON_ERROR_NONE !== json_last_error()) {
throw new BadRequestHttpException(sprintf('json_decode error: %s', json_last_error_msg()));
}

foreach ($members as $member) {
$memberCollection->add($this->memberFactory->create($member));
}
}

$membership->setMembers($memberCollection);

$this->repository->save($membership);
$this->service->updateMembership($membership, $members);

$this->flashBag->add('success', sprintf('Membership %s edition success', $formData['membership_id']));

Expand Down
27 changes: 23 additions & 4 deletions src/Nrps/MembershipRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

namespace App\Nrps;

use OAT\Library\Lti1p3Nrps\Model\Member\MemberCollection;
use OAT\Library\Lti1p3Nrps\Model\Member\MemberInterface;
use OAT\Library\Lti1p3Nrps\Model\Membership\MembershipInterface;
use Psr\Cache\CacheItemPoolInterface;

Expand All @@ -37,19 +39,36 @@ public function __construct(CacheItemPoolInterface $cache)
$this->cache = $cache;
}

public function find(string $identifier): ?MembershipInterface
{
public function find(
string $identifier,
?array $statuses = [MemberInterface::STATUS_ACTIVE, MemberInterface::STATUS_INACTIVE]
): ?MembershipInterface {
$membership = null;
$cache = $this->cache->getItem(self::CACHE_KEY);

if ($cache->isHit()) {
$memberships = $cache->get();

if (array_key_exists($identifier, $memberships)) {
return $memberships[$identifier];
/** @var MembershipInterface $membership */
$membership = $memberships[$identifier];

if (null !== $statuses) {
$membership->setMembers(
new MemberCollection(
array_filter(
$membership->getMembers()->all(),
static function (MemberInterface $member) use ($statuses) {
return in_array($member->getStatus(), $statuses, true);
}
)
)
);
}
}
}

return null;
return $membership;
}

public function findAll(): array
Expand Down
101 changes: 101 additions & 0 deletions src/Nrps/MembershipService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2022 (original work) Open Assessment Technologies SA;
*
* @author Sergei Mikhailov <sergei.mikhailov@taotesting.com>
*/

declare(strict_types=1);

namespace App\Nrps;

use OAT\Library\Lti1p3Nrps\Factory\Member\MemberFactoryInterface;
use OAT\Library\Lti1p3Nrps\Model\Member\MemberCollection;
use OAT\Library\Lti1p3Nrps\Model\Member\MemberInterface;
use OAT\Library\Lti1p3Nrps\Model\Membership\MembershipInterface;

class MembershipService
{
public const UPDATED_AT_FIELD = 'updated_at';

/** @var MembershipRepository */
private $repository;

/** @var MemberFactoryInterface */
private $memberFactory;

public function __construct(MembershipRepository $repository, MemberFactoryInterface $memberFactory)
{
$this->repository = $repository;
$this->memberFactory = $memberFactory;
}

public function findMembership(string $identifier, array $statuses = null): ?MembershipInterface
{
return $this->repository->find($identifier, $statuses);
}

public function updateMembership(MembershipInterface $membership, array $rawMembers): void
{
$memberCollection = new MemberCollection();
$now = time();

foreach ($rawMembers as $member) {
unset($member[static::UPDATED_AT_FIELD]);
$newMember = $this->memberFactory->create($member);

if (!$membership->getMembers()->has($newMember->getUserIdentity()->getIdentifier())) {
$this->setUpdatedAtToMember($newMember, $now);
}

$memberCollection->add($newMember);
}

/** @var MemberInterface $existingMember */
foreach ($membership->getMembers() as $existingMember) {
$existingMemberUpdatedAt = $existingMember->getProperties()->get(static::UPDATED_AT_FIELD);
$existingMember->getProperties()->remove(static::UPDATED_AT_FIELD);
$memberId = $existingMember->getUserIdentity()->getIdentifier();

if (!$memberCollection->has($memberId)) {
$this->setUpdatedAtToMember($existingMember, $now);
$existingMember->setStatus(MemberInterface::STATUS_DELETED)
->getProperties()->add(['status' => MemberInterface::STATUS_DELETED]);

$memberCollection->add($existingMember);
} else {
$member = $memberCollection->get($memberId);
$this->setUpdatedAtToMember(
$member,
$existingMemberUpdatedAt && $member == $existingMember
? $existingMemberUpdatedAt
: $now
);
}
}

$membership->setMembers($memberCollection);

$this->repository->save($membership);
}

private function setUpdatedAtToMember(MemberInterface $member, int $now): void
{
$member->getProperties()->add([static::UPDATED_AT_FIELD => $now]);
}
}
Loading

0 comments on commit b6a4abe

Please sign in to comment.