Messages: Add MessageTagVoter.php, add tests, remove unused code

Minor UI changes
pull/3924/head
Julio Montoya 3 years ago
parent a8c2f6840f
commit 8ae7ab69b7
  1. 12
      assets/vue/components/Toolbar.vue
  2. 18
      assets/vue/components/layout/DashboardLayout.vue
  3. 24
      assets/vue/views/message/List.vue
  4. 24
      public/main/inc/ajax/message.ajax.php
  5. 2
      src/CoreBundle/DataProvider/Extension/CDocumentExtension.php
  6. 8
      src/CoreBundle/DataProvider/Extension/MessageExtension.php
  7. 52
      src/CoreBundle/DataProvider/Extension/MessageTagExtension.php
  8. 7
      src/CoreBundle/Entity/Message.php
  9. 10
      src/CoreBundle/Entity/MessageTag.php
  10. 27
      src/CoreBundle/Entity/PersonalFile.php
  11. 19
      src/CoreBundle/Entity/User.php
  12. 33
      src/CoreBundle/Entity/UserRelUser.php
  13. 84
      src/CoreBundle/Security/Authorization/Voter/MessageTagVoter.php
  14. 10
      src/CoreBundle/Security/Authorization/Voter/MessageVoter.php
  15. 8
      tests/AbstractApiTest.php
  16. 72
      tests/CoreBundle/Repository/MessageRepositoryTest.php
  17. 119
      tests/CoreBundle/Repository/MessageTagRepositoryTest.php
  18. 182
      tests/CoreBundle/Repository/Node/PersonalFileRepositoryTest.php

@ -104,6 +104,18 @@
File upload
</q-btn>
<!-- <v-btn-->
<!-- v-if="handleUploadDocument"-->
<!-- :loading="isLoading"-->
<!-- tile-->
<!-- icon-->
<!-- @click="uploadDocument"-->
<!-- >-->
<!-- <v-icon icon="mdi-cloud-upload"/>-->
<!-- </v-btn>-->
<!-- <DataFilter-->
<!-- v-if="filters"-->
<!-- :handle-filter="onSendFilter"-->

@ -33,13 +33,9 @@
<q-space />
<div class="q-gutter-sm row items-center no-wrap">
<!-- <q-btn v-if="$q.screen.gt.sm" round dense flat color="text-grey-7" icon="apps">-->
<!-- <q-tooltip>Google Apps</q-tooltip>-->
<!-- </q-btn>-->
<q-btn v-if="isAuthenticated" round dense flat color="grey-8" icon="person">
<q-tooltip>Account</q-tooltip>
</q-btn>
<!-- <q-btn v-if="isAuthenticated" round dense flat color="grey-8" icon="people">-->
<!-- <q-tooltip>Friends</q-tooltip>-->
<!-- </q-btn>-->
<q-btn v-if="isAuthenticated" round dense flat color="grey-8"
icon="inbox"
@ -51,6 +47,14 @@
<q-tooltip>Inbox</q-tooltip>
</q-btn>
<q-btn
v-if="isAuthenticated" round dense flat color="grey-8" icon="folder"
:to="'/resources/personal_files/' + currentUser.resourceNode.id"
>
<q-tooltip>Files</q-tooltip>
</q-btn>
<q-btn v-if="isAuthenticated" round dense flat color="grey-8" icon="notifications">
<q-badge color="red" text-color="white" floating>
2

@ -20,25 +20,31 @@
<v-btn
tile
icon
@click="confirmDeleteMultiple" :disabled="!selectedItems || !selectedItems.length" >
@click="confirmDeleteMultiple"
:class="[ !selectedItems || !selectedItems.length ? 'hidden': '']"
>
<v-icon icon="mdi-delete" />
</v-btn>
<!-- :disabled="!selectedItems || !selectedItems.length"-->
<v-btn
icon
tile
@click="markAsUnReadMultiple" :disabled="!selectedItems || !selectedItems.length" >
@click="markAsUnReadMultiple"
:class="[ !selectedItems || !selectedItems.length ? 'hidden': '']"
>
<v-icon icon="mdi-email" />
</v-btn>
<v-btn
tile
icon
@click="markAsReadMultiple" :disabled="!selectedItems || !selectedItems.length" >
:class="[ !selectedItems || !selectedItems.length ? 'hidden': '']"
>
<v-icon icon="mdi-email-open" />
</v-btn>
</div>
</div>
</div>
@ -48,7 +54,7 @@
<v-card
max-width="300"
tile
>
>
<v-list dense>
<!-- v-model="selectedItem"-->
<v-list-item-group
@ -124,7 +130,7 @@
<Column selectionMode="multiple" style="width: 3rem" :exportable="false"></Column>
<Column field="userSender" :header="$t('Sender')" :sortable="true">
<Column field="userSender" :header="$t('From')" :sortable="false">
<template #body="slotProps">
<q-avatar size="40px">
<img :src="slotProps.data.userSender.illustrationUrl + '?w=80&h=80&fit=crop'" />
@ -134,7 +140,7 @@
v-if="slotProps.data"
@click="showHandler(slotProps.data)"
class="cursor-pointer"
v-bind:class="[ true === slotProps.data.read ? 'font-normal': 'font-semibold']"
:class="[ true === slotProps.data.read ? 'font-normal': 'font-semibold']"
>
{{ slotProps.data.userSender.username }}
</a>
@ -142,7 +148,7 @@
</Column>
<Column field="title" :header="$t('Title')" :sortable="true">
<Column field="title" :header="$t('Title')" :sortable="false">
<template #body="slotProps">
<a
v-if="slotProps.data"

@ -14,30 +14,6 @@ require_once __DIR__.'/../global.inc.php';
$action = $_GET['a'];
switch ($action) {
case 'get_notifications_inbox':
$userId = api_get_user_id();
$listInbox = [];
if ('true' === api_get_setting('allow_message_tool')) {
$list = MessageManager::getMessageData(
0,
10,
null,
null,
['actions' => ['read'], 'type' => Message::MESSAGE_TYPE_INBOX]
);
foreach ($list as $row) {
$user = api_get_user_info($row['0']);
$temp['title'] = $row['1'];
$temp['date'] = $row['2'];
$temp['fullname'] = $user['complete_name'];
$temp['email'] = $user['email'];
$temp['url'] = $row['1'];
$listInbox[] = $temp;
}
}
header('Content-type:application/json');
echo json_encode($listInbox);
break;
case 'get_notifications_friends':
$userId = api_get_user_id();
$listInvitations = [];

@ -72,8 +72,6 @@ final class CDocumentExtension implements QueryCollectionExtensionInterface //,
throw new AccessDeniedException('cid is required');
}
error_log('addWhere');
error_log('here!');
$rootAlias = $queryBuilder->getRootAliases()[0];
$queryBuilder

@ -25,9 +25,9 @@ final class MessageExtension implements QueryCollectionExtensionInterface //, Qu
public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null): void
{
if ($this->security->isGranted('ROLE_ADMIN')) {
/*if ($this->security->isGranted('ROLE_ADMIN')) {
return;
}
}*/
/*
if ('collection_query' === $operationName) {
if (null === $user = $this->security->getUser()) {
@ -54,9 +54,9 @@ final class MessageExtension implements QueryCollectionExtensionInterface //, Qu
return;
}
if ($this->security->isGranted('ROLE_ADMIN')) {
/*if ($this->security->isGranted('ROLE_ADMIN')) {
return;
}
}*/
$user = $this->security->getUser();

@ -0,0 +1,52 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\DataProvider\Extension;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
//use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Chamilo\CoreBundle\Entity\Message;
use Chamilo\CoreBundle\Entity\MessageTag;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;
final class MessageTagExtension implements QueryCollectionExtensionInterface //, QueryItemExtensionInterface
{
private Security $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null): void
{
$this->addWhere($queryBuilder, $resourceClass);
}
/*public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = []): void
{
//error_log('applyToItem');
//$this->addWhere($queryBuilder, $resourceClass);
}*/
private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
{
if (MessageTag::class !== $resourceClass) {
return;
}
$user = $this->security->getUser();
$alias = $queryBuilder->getRootAliases()[0];
$queryBuilder->andWhere(" $alias.user = :current ");
$queryBuilder->setParameters([
'current' => $user,
]);
}
}

@ -7,7 +7,6 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
@ -37,9 +36,11 @@ use Symfony\Component\Validator\Constraints as Assert;
*/
#[ApiResource(
collectionOperations: [
'get' => [],
'get' => [
'security' => "is_granted('ROLE_USER')", // the get collection is also filtered by MessageExtension
],
'post' => [
'security' => "is_granted('ROLE_USER')",
'security_post_denormalize' => "is_granted('CREATE', object)",
// 'deserialize' => false,
// 'controller' => Create::class,
// 'openapi_context' => [

@ -39,21 +39,21 @@ use Symfony\Component\Validator\Constraints as Assert;
#[ApiResource(
collectionOperations: [
'get' => [
//'security' => "is_granted('ROLE_ADMIN')",
'security' => "is_granted('ROLE_USER')", // the get collection is also filtered by MessageTagExtension
],
'post' => [
//'security' => "is_granted('ROLE_ADMIN') or object.user == user",
'security_post_denormalize' => "is_granted('CREATE', object)",
],
],
itemOperations: [
'get' => [
//'security' => "is_granted('ROLE_ADMIN')",
'security' => "is_granted('VIEW', object)",
],
'put' => [
//'security' => "is_granted('ROLE_ADMIN') or object.user == user",
'security' => "is_granted('EDIT', object)",
],
'delete' => [
//'security' => "is_granted('ROLE_ADMIN') or object.user == user",
'security' => "is_granted('DELETE', object)",
],
],
attributes: [

@ -93,23 +93,26 @@ use Symfony\Component\Validator\Constraints as Assert;
* },
* },
* )
* @ApiFilter(SearchFilter::class, properties={"title":"partial", "resourceNode.parent":"exact"})
* @ApiFilter(PropertyFilter::class)
* @ApiFilter(
* OrderFilter::class,
* properties={
* "id",
* "resourceNode.title",
* "resourceNode.createdAt",
* "resourceNode.resourceFile.size",
* "resourceNode.updatedAt"
* }
* )
*
* @ORM\EntityListeners({"Chamilo\CoreBundle\Entity\Listener\ResourceListener"})
* @ORM\Table(name="personal_file")
* @ORM\Entity
*/
#[ApiFilter(SearchFilter::class, properties: [
'title' => 'partial',
'resourceNode.parent' => 'partial',
])]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(OrderFilter::class, properties: [
'id',
'resourceNode.title',
'resourceNode.createdAt',
'resourceNode.resourceFile.size',
'resourceNode.updatedAt',
]
)]
class PersonalFile extends AbstractResource implements ResourceInterface
{
use TimestampableEntity;

@ -39,17 +39,17 @@ use UserManager;
* EquatableInterface is needed to check if the user needs to be refreshed.
*
* @ApiResource(
* attributes={"security"="is_granted('ROLE_ADMIN')"},
* attributes={"security"="is_granted('ROLE_USER')"},
* iri="http://schema.org/Person",
* normalizationContext={"groups"={"user:read"}},
* denormalizationContext={"groups"={"user:write"}},
* collectionOperations={
* "get"={"security"="is_granted('ROLE_ADMIN')"},
* "post"={"security"="is_granted('ROLE_ADMIN')"}
* "get"={"security"="is_granted('ROLE_USER')"},
* "post"={"security"="is_granted('ROLE_USER')"}
* },
* itemOperations={
* "get"={"security"="is_granted('ROLE_ADMIN')"},
* "put"={"security"="is_granted('ROLE_ADMIN')"},
* "get"={"security"="is_granted('ROLE_USER')"},
* "put"={"security"="is_granted('ROLE_USER')"},
* },
* )
*
@ -1301,6 +1301,15 @@ class User implements UserInterface, EquatableInterface, ResourceInterface, Reso
return $this->id;
}
public function getIri(): ?string
{
if (null === $this->id) {
return null;
}
return '/api/users/'.$this->getId();
}
public function getSlug(): string
{
return $this->getUsername();

@ -6,12 +6,13 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Chamilo\CoreBundle\Traits\UserTrait;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
/**
* Associations between users (friends).
* Associations between users.
*
* @ORM\Table(name="user_rel_user", indexes={
* @ORM\Index(name="idx_user_rel_user__user", columns={"user_id"}),
@ -20,6 +21,36 @@ use Doctrine\ORM\Mapping as ORM;
* })
* @ORM\Entity
*/
#[ApiResource(
collectionOperations: [
'get' => [
//'security' => "is_granted('ROLE_ADMIN')",
],
'post' => [
//'security' => "is_granted('ROLE_ADMIN') or object.user == user",
],
],
itemOperations: [
'get' => [
//'security' => "is_granted('ROLE_ADMIN')",
],
'put' => [
//'security' => "is_granted('ROLE_ADMIN') or object.user == user",
],
'delete' => [
//'security' => "is_granted('ROLE_ADMIN') or object.user == user",
],
],
attributes: [
'security' => 'is_granted("ROLE_USER") and object.user == user',
],
denormalizationContext: [
'groups' => ['message_tag:write'],
],
normalizationContext: [
'groups' => ['message_tag:read'],
],
)]
class UserRelUser
{
use UserTrait;

@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Security\Authorization\Voter;
use Chamilo\CoreBundle\Entity\Message;
use Chamilo\CoreBundle\Entity\MessageTag;
use Chamilo\CoreBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
class MessageTagVoter extends Voter
{
public const CREATE = 'CREATE';
public const VIEW = 'VIEW';
public const EDIT = 'EDIT';
public const DELETE = 'DELETE';
private EntityManagerInterface $entityManager;
private Security $security;
public function __construct(
EntityManagerInterface $entityManager,
Security $security
) {
$this->entityManager = $entityManager;
$this->security = $security;
}
protected function supports(string $attribute, $subject): bool
{
$options = [
self::CREATE,
self::VIEW,
self::EDIT,
self::DELETE,
];
// if the attribute isn't one we support, return false
if (!\in_array($attribute, $options, true)) {
return false;
}
// only vote on Post objects inside this voter
return $subject instanceof MessageTag;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
/** @var User $user */
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return false;
}
if ($this->security->isGranted('ROLE_ADMIN')) {
return true;
}
/** @var MessageTag $message */
$message = $subject;
switch ($attribute) {
case self::CREATE:
case self::VIEW:
case self::EDIT:
case self::DELETE:
if ($message->getUser() === $user) {
return true;
}
break;
}
return false;
}
}

@ -16,6 +16,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
class MessageVoter extends Voter
{
public const CREATE = 'CREATE';
public const VIEW = 'VIEW';
public const EDIT = 'EDIT';
public const DELETE = 'DELETE';
@ -34,6 +35,7 @@ class MessageVoter extends Voter
protected function supports(string $attribute, $subject): bool
{
$options = [
self::CREATE,
self::VIEW,
self::EDIT,
self::DELETE,
@ -57,7 +59,7 @@ class MessageVoter extends Voter
return false;
}
// Admins have access to everything
// Admins have access to everything.
if ($this->security->isGranted('ROLE_ADMIN')) {
return true;
}
@ -66,6 +68,12 @@ class MessageVoter extends Voter
$message = $subject;
switch ($attribute) {
case self::CREATE:
if ($message->getUserSender() === $user) {
return true;
}
break;
case self::VIEW:
if ($message->getUserReceiver() === $user) {
return true;

@ -52,9 +52,13 @@ abstract class AbstractApiTest extends ApiTestCase
/**
* Use credentials with token.
*/
protected function getUserToken($body = []): string
protected function getUserToken($body = [], $cleanToken = false): string
{
if ($this->token) {
if ($cleanToken) {
$this->token = null;
}
if (null !== $this->token) {
return $this->token;
}

@ -10,13 +10,13 @@ use Chamilo\CoreBundle\Entity\Message;
use Chamilo\CoreBundle\Entity\MessageTag;
use Chamilo\CoreBundle\Repository\MessageRepository;
use Chamilo\CoreBundle\Repository\MessageTagRepository;
use Chamilo\Tests\AbstractApiTest;
use Chamilo\Tests\ChamiloTestTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/**
* @covers \MessageRepository
*/
class MessageRepositoryTest extends WebTestCase
class MessageRepositoryTest extends AbstractApiTest
{
use ChamiloTestTrait;
@ -83,4 +83,72 @@ class MessageRepositoryTest extends WebTestCase
$this->assertSame(2, $message->getTags()->count());
}
public function testCreateMessageWithApi(): void
{
self::bootKernel();
$fromUser = $this->createUser('from');
$toUser = $this->createUser('to');
$tokenFrom = $this->getUserToken(
[
'username' => 'from',
'password' => 'from',
]
);
$this->createClientWithCredentials($tokenFrom)->request(
'POST',
'/api/messages',
[
'json' => [
'title' => 'hello',
'content' => 'content of hello',
'msgType' => Message::MESSAGE_TYPE_INBOX,
'userSender' => '/api/users/'.$fromUser->getId(),
'userReceiver' => '/api/users/'.$toUser->getId(),
],
]
);
$this->assertResponseIsSuccessful();
$this->assertResponseStatusCodeSame(201);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains(
[
'@context' => '/api/contexts/Message',
'@type' => 'Message',
'title' => 'hello',
'read' => false,
'starred' => false,
]
);
// Try to send a message as another user
$this->createUser('bad');
$tokenFromBadUser = $this->getUserToken(
[
'username' => 'bad',
'password' => 'bad',
],
true
);
$this->createClientWithCredentials($tokenFromBadUser)->request(
'POST',
'/api/messages',
[
'json' => [
'title' => 'hello',
'content' => 'content of hello',
'msgType' => Message::MESSAGE_TYPE_INBOX,
'userSender' => '/api/users/'.$fromUser->getId(),
'userReceiver' => '/api/users/'.$toUser->getId(),
],
]
);
$this->assertResponseStatusCodeSame(403);
}
}

@ -9,6 +9,7 @@ namespace Chamilo\Tests\CoreBundle\Repository;
use Chamilo\CoreBundle\Entity\MessageTag;
use Chamilo\CoreBundle\Repository\MessageTagRepository;
use Chamilo\CoreBundle\Repository\Node\UserRepository;
use Chamilo\Tests\AbstractApiTest;
use Chamilo\Tests\ChamiloTestTrait;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
@ -16,7 +17,7 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/**
* @covers \MessageTagRepository
*/
class MessageTagRepositoryTest extends WebTestCase
class MessageTagRepositoryTest extends AbstractApiTest
{
use ChamiloTestTrait;
@ -33,7 +34,7 @@ class MessageTagRepositoryTest extends WebTestCase
->setTag('my tag')
->setColor('red')
->setUser($testUser)
;
;
$this->assertHasNoEntityViolations($tag);
$tagRepo->update($tag);
@ -48,7 +49,6 @@ class MessageTagRepositoryTest extends WebTestCase
$count = $tagRepo->count([]);
$this->assertSame(0, $count);
$this->assertSame(0, $tag->getPosition());
}
@ -74,6 +74,7 @@ class MessageTagRepositoryTest extends WebTestCase
->setTag('tag 2')
->setUser($testUser)
;
$this->assertHasNoEntityViolations($tag2);
$tagRepo->update($tag2);
@ -94,16 +95,16 @@ class MessageTagRepositoryTest extends WebTestCase
(new MessageTag())
->setTag('unique')
->setUser($testUser)
;
;
$this->assertHasNoEntityViolations($tag);
$tagRepo->update($tag);
// Create second tag, with same name + same user
// Create second tag, with same name + same user, should fail.
$tag =
(new MessageTag())
->setTag('unique')
->setUser($testUser)
;
;
$violations = $this->getViolations($tag);
$this->assertSame(1, $violations->count());
@ -113,4 +114,110 @@ class MessageTagRepositoryTest extends WebTestCase
$count = $tagRepo->count([]);
$this->assertSame(1, $count);
}
public function testCreateTagWithApi(): void
{
self::bootKernel();
$testUser = $this->createUser('test');
$token = $this->getUserToken(
[
'username' => 'test',
'password' => 'test',
]
);
$response = $this->createClientWithCredentials($token)->request(
'POST',
'/api/message_tags',
[
'json' => [
'tag' => 'my tag',
'user' => $testUser->getIri(),
],
]
);
$this->assertResponseIsSuccessful();
$this->assertResponseStatusCodeSame(201);
// Check if the tag exists.
$this->createClientWithCredentials($token)->request(
'GET',
'/api/message_tags',
);
$this->assertResponseStatusCodeSame(200);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains(
[
'@context' => '/api/contexts/MessageTag',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 1,
]
);
// Fails to add the same tag twice.
$this->createClientWithCredentials($token)->request(
'POST',
'/api/message_tags',
[
'json' => [
'tag' => 'my tag',
'user' => $testUser->getIri(),
],
]
);
$this->assertResponseStatusCodeSame(422);
// Update tag.
$id = $response->toArray()['id'];
$this->createClientWithCredentials($token)->request(
'PUT',
'/api/message_tags/'.$id,
[
'json' => [
'tag' => 'my tag 2',
],
]
);
$this->assertResponseIsSuccessful();
$this->assertResponseStatusCodeSame(200);
// Add tag as another user
$this->createUser('bad');
$otherToken = $this->getUserToken(
[
'username' => 'bad',
'password' => 'bad',
],
true
);
// Fails to POST a tag to another user.
$this->createClientWithCredentials($otherToken)->request(
'POST',
'/api/message_tags',
[
'json' => [
'tag' => 'new tag',
'user' => $testUser->getIri(),
],
]
);
$this->assertResponseStatusCodeSame(403);
$this->createClientWithCredentials($otherToken)->request(
'GET',
'/api/message_tags',
);
$this->assertResponseStatusCodeSame(200);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains(
[
'@context' => '/api/contexts/MessageTag',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 0,
]
);
}
}

@ -17,6 +17,29 @@ class PersonalFileRepositoryTest extends AbstractApiTest
{
use ChamiloTestTrait;
public function testAccessAsAnon(): void
{
$admin = $this->getUser('admin');
$client = static::createClient();
$client->request('GET', '/api/personal_files');
$this->assertResponseStatusCodeSame(401);
$client->request('POST', '/api/personal_files');
$this->assertResponseStatusCodeSame(401);
$client->request(
'GET',
'/api/personal_files',
[
'json' => [
'resourceNode.parent' => $admin->getResourceNode()->getId(),
],
]
);
$this->assertResponseStatusCodeSame(401);
}
public function testCreateFolder(): void
{
$username = 'test';
@ -24,10 +47,12 @@ class PersonalFileRepositoryTest extends AbstractApiTest
$user = $this->createUser($username, $password);
$folderName = 'folder1';
$token = $this->getUserToken([
'username' => $username,
'password' => $password,
]);
$token = $this->getUserToken(
[
'username' => $username,
'password' => $password,
]
);
$resourceNodeId = $user->getResourceNode()->getId();
@ -46,15 +71,17 @@ class PersonalFileRepositoryTest extends AbstractApiTest
$this->assertResponseIsSuccessful();
$this->assertResponseStatusCodeSame(201);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/api/contexts/PersonalFile',
'@type' => 'PersonalFile',
'title' => $folderName,
'parentResourceNode' => $resourceNodeId,
]);
$this->assertJsonContains(
[
'@context' => '/api/contexts/PersonalFile',
'@type' => 'PersonalFile',
'title' => $folderName,
'parentResourceNode' => $resourceNodeId,
]
);
}
public function testFileUpload(): void
public function testFileUploadAndShare(): void
{
self::bootKernel();
$username = 'sender';
@ -63,20 +90,17 @@ class PersonalFileRepositoryTest extends AbstractApiTest
// Creates "sender" user.
$user = $this->createUser($username, $password);
$token = $this->getUserToken([
'username' => $username,
'password' => $password,
]);
$token = $this->getUserToken(
[
'username' => $username,
'password' => $password,
]
);
// Creates "receiver" user.
$receiverUsername = 'receiver';
$receiverPassword = 'receiver';
$receiverUser = $this->createUser($receiverUsername, $receiverPassword);
$receiverToken = $this->getUserToken([
'username' => $receiverUsername,
'password' => $receiverPassword,
]);
$resourceNodeId = $user->getResourceNode()->getId();
$file = $this->getUploadedFile();
@ -106,21 +130,25 @@ class PersonalFileRepositoryTest extends AbstractApiTest
$this->assertResponseIsSuccessful();
$this->assertResponseStatusCodeSame(201);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/api/contexts/PersonalFile',
'@type' => 'PersonalFile',
'title' => $fileName,
'parentResourceNode' => $resourceNodeId,
]);
$this->assertJsonContains(
[
'@context' => '/api/contexts/PersonalFile',
'@type' => 'PersonalFile',
'title' => $fileName,
'parentResourceNode' => $resourceNodeId,
]
);
// File URL.
$url = $response->toArray()['contentUrl'];
$personalFileId = $response->toArray()['id'];
$resourceLinkList = [[
'uid' => $receiverUser->getId(),
'visibility' => $visibilityPublished,
]];
$resourceLinkList = [
[
'uid' => $receiverUser->getId(),
'visibility' => $visibilityPublished,
],
];
// Share PersonalFile with user 'receiver'.
$this->createClientWithCredentials($token)->request(
@ -136,24 +164,26 @@ class PersonalFileRepositoryTest extends AbstractApiTest
$this->assertResponseIsSuccessful();
$this->assertResponseStatusCodeSame(200);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/api/contexts/PersonalFile',
'@type' => 'PersonalFile',
'title' => $fileName,
'id' => $personalFileId,
'resourceLinkListFromEntity' => [
[
'visibility' => $visibilityPublished,
'session' => null,
'course' => null,
'group' => null,
'userGroup' => null,
'user' => [
'id' => $receiverUser->getId(),
$this->assertJsonContains(
[
'@context' => '/api/contexts/PersonalFile',
'@type' => 'PersonalFile',
'title' => $fileName,
'id' => $personalFileId,
'resourceLinkListFromEntity' => [
[
'visibility' => $visibilityPublished,
'session' => null,
'course' => null,
'group' => null,
'userGroup' => null,
'user' => [
'id' => $receiverUser->getId(),
],
],
],
],
]);
]
);
// Access Checks.
@ -197,4 +227,64 @@ class PersonalFileRepositoryTest extends AbstractApiTest
);
$this->assertResponseIsSuccessful();
}
public function testUserUploadFileAsAnotherUser(): void
{
self::bootKernel();
$username = 'sender';
$password = 'sender';
// Creates "sender" user.
$user = $this->createUser($username, $password);
$this->createUser('bad', 'bad');
$badUserToken = $this->getUserToken(
[
'username' => 'bad',
'password' => 'bad',
],
true
);
// 1. This is the original user.
$resourceNodeId = $user->getResourceNode()->getId();
$file = $this->getUploadedFile();
// 2. "bad user" tries to upload file to the original user.
$this->createClientWithCredentials($badUserToken)->request(
'POST',
'/api/personal_files',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
'extra' => [
'files' => [
'uploadFile' => $file,
],
],
'json' => [
'filetype' => 'file',
'size' => $file->getSize(),
'parentResourceNodeId' => $resourceNodeId,
],
]
);
$this->assertResponseStatusCodeSame(401);
// Bad user tries to get files from other user
$this->createClientWithCredentials($badUserToken)->request(
'GET',
'/api/personal_files',
[
'json' => [
'parentResourceNodeId' => $resourceNodeId,
],
]
);
$this->assertResponseStatusCodeSame(401);
}
}

Loading…
Cancel
Save