refs #379. Fixed error UserInput create

pull/5/head
Manuel Aranda Rosales 2024-05-29 21:48:54 +02:00
parent 82ea76a557
commit b652f70973
10 changed files with 127 additions and 20 deletions

View File

@ -5,6 +5,14 @@
ogCore es el servicio central de OpenGnsys, diseñado para proporcionar funcionalidades a través de una API RESTful. Esta herramienta utiliza tecnología PHP, aprovechando el framework Symfony y el ORM Doctrine para gestionar la base de datos.
A continuación, se detallan los pasos necesarios para desplegar el proyecto en un entorno de desarrollo.
## Versiones y tecnologías utilizadas
- PHP 8.3
- Symfony 6.4
- Doctrine 2.19
- API Platform 3.2
- MariaDB 10.11
## Requisitos
Antes de comenzar, asegúrate de tener los siguientes requisitos:
@ -46,7 +54,7 @@ Comprobamos, que el contenedor de Nginx, tiene el puerto 8080 levantado correcta
acceder a la siguiente URL:
```sh
http://127.0.0.1:8080/api/docs
http://127.0.0.1:8080/docs
```
Si todo ha ido bien, deberiamos ver la documentación de la API de ogCore.
@ -68,7 +76,7 @@ docker exec ogcore-php php bin/console app:load-default-user-groups
Api Platform proporciona una interfaz de usuario para interactuar con la API de ogCore. Para acceder a la interfaz de usuario, accede a la siguiente URL:
```sh
http://127.0.0.1:8080/api/docs
http://127.0.0.1:8080/docs
```
Para poder autenticarte, necesitas un token JWT. Para obtenerlo, accedemos al endpoint de autenticación "auth/login":

View File

@ -27,7 +27,7 @@ security:
access_control:
- { path: ^/$, roles: PUBLIC_ACCESS } # Allows accessing the Swagger UI
- { path: ^/api/docs, roles: PUBLIC_ACCESS } # Allows accessing the Swagger UI docs
- { path: ^/docs, roles: PUBLIC_ACCESS } # Allows accessing the Swagger UI docs
- { path: ^/auth/login, roles: PUBLIC_ACCESS }
- { path: ^/auth/refresh, roles: PUBLIC_ACCESS }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }

View File

@ -1,4 +1,3 @@
api_platform:
resource: .
type: api_platform
prefix: /api

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240529131520 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D727ACA70');
$this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (id) ON DELETE SET NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D727ACA70');
$this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (id)');
}
}

View File

@ -2,6 +2,8 @@
namespace App\DataFixtures;
use App\Entity\OrganizationalUnit;
use App\Factory\OrganizationalUnitFactory;
use App\Factory\UserFactory;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
@ -10,12 +12,22 @@ class AppFixtures extends Fixture
{
CONST ADMIN_USER = 'ogadmin';
/**
* @throws \Exception
*/
public function load(ObjectManager $manager): void
{
UserFactory::createOne(['username' => self::ADMIN_USER]);
$rootUnit = OrganizationalUnitFactory::createOne(['name' => 'Centro de Computación', 'parent' => null]);
$roomUnit = OrganizationalUnitFactory::createOne([
'name' => 'Aula 1',
'parent' => $rootUnit
]);
OrganizationalUnitFactory::createOne([
'name' => 'Aula 2',
'parent' => $roomUnit
]);
}
}

View File

@ -2,6 +2,8 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\UserGroupOutput;
use App\Entity\OrganizationalUnit;
use App\Entity\User;
use App\Entity\UserGroup;
@ -14,13 +16,11 @@ final class UserInput
#[Groups(['user:write'])]
public ?string $username = null;
#[Groups(['user:write'])]
public array $roles = [];
/**
* @var OrganizationalUnit[]
*/
#[Groups(['user:write'])]
#[ApiProperty(readableLink: false, writableLink: false)]
public array $allowedOrganizationalUnits = [];
#[Assert\NotBlank(groups: ['user:post'])]
@ -36,6 +36,7 @@ final class UserInput
* @var UserGroup[]
*/
#[Groups(['user:write'])]
#[ApiProperty(readableLink: false, writableLink: false)]
public array $userGroups = [];
public function __construct(?User $user = null)
@ -45,7 +46,6 @@ final class UserInput
}
$this->username = $user->getUsername();
$this->roles = $user->getRoles();
$this->enabled= $user->isEnabled();
$this->userGroups = $user->getUserGroups()->toArray();
$this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->toArray();
@ -58,7 +58,6 @@ final class UserInput
}
$user->setUsername($this->username);
$user->setRoles($this->roles);
$user->setEnabled($this->enabled);
foreach ($this->userGroups as $userGroup) {

View File

@ -35,6 +35,7 @@ class OrganizationalUnit extends AbstractEntity
#[Gedmo\TreeParent]
#[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'organizationalUnits')]
#[ORM\JoinColumn( onDelete: 'SET NULL')]
private ?self $parent = null;
/**

View File

@ -0,0 +1,54 @@
<?php
namespace App\Factory;
use App\Entity\OrganizationalUnit;
use Gedmo\Tree\Entity\Repository\MaterializedPathRepository;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Proxy;
use Zenstruck\Foundry\RepositoryProxy;
/**
* @extends ModelFactory<OrganizationalUnit>
*/
final class OrganizationalUnitFactory extends ModelFactory
{
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
*
* @todo inject services if required
*/
public function __construct()
{
parent::__construct();
}
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
*
* @todo add your default values here
*/
protected function getDefaults(): array
{
return [
'createdAt' => self::faker()->dateTime(),
'name' => self::faker()->text(255),
'updatedAt' => self::faker()->dateTime(),
];
}
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
*/
protected function initialize(): self
{
return $this
// ->afterInstantiate(function(OrganizationalUnit $organizationalUnit): void {})
;
}
protected static function getClass(): string
{
return OrganizationalUnit::class;
}
}

View File

@ -38,12 +38,12 @@ class UserGroupTest extends AbstractTest
UserGroupFactory::createOne(['name' => 'Operador de aulas', 'permissions' => ['ROLE_ORGANIZATIONAL_UNIT_OPERATOR'], 'enabled' => true]);
UserGroupFactory::createOne(['name' => 'Usuario', 'permissions' => ['ROLE_USER'], 'enabled' => true]);
$this->createClientWithCredentials()->request('GET', '/api/user-groups');
$this->createClientWithCredentials()->request('GET', '/user-groups');
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/api/contexts/UserGroup',
'@id' => '/api/user-groups',
'@context' => '/contexts/UserGroup',
'@id' => '/user-groups',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 4,
]);
@ -59,7 +59,7 @@ class UserGroupTest extends AbstractTest
public function testCreateUserGroup(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN]);
$this->createClientWithCredentials()->request('POST', '/api/user-groups',['json' => [
$this->createClientWithCredentials()->request('POST', '/user-groups',['json' => [
'name' => self::USER_GROUP_CREATE,
'enabled' => true,
]]);
@ -67,7 +67,7 @@ class UserGroupTest extends AbstractTest
$this->assertResponseStatusCodeSame(201);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/api/contexts/UserGroupOutput',
'@context' => '/contexts/UserGroupOutput',
'@type' => 'UserGroup',
'name' => self::USER_GROUP_CREATE,
'enabled' => true,

View File

@ -30,12 +30,12 @@ class UserTest extends AbstractTest
UserFactory::createOne(['username' => self::USER_ADMIN]);
UserFactory::createMany(10);
$this->createClientWithCredentials()->request('GET', '/api/users');
$this->createClientWithCredentials()->request('GET', '/users');
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/api/contexts/User',
'@id' => '/api/users',
'@context' => '/contexts/User',
'@id' => '/users',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 11,
]);
@ -51,7 +51,7 @@ class UserTest extends AbstractTest
public function testCreateUser(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN]);
$this->createClientWithCredentials()->request('POST', '/api/users',['json' => [
$this->createClientWithCredentials()->request('POST', '/users',['json' => [
'username' => self::USER_CREATE,
'password' => '12345678',
'enabled' => true,
@ -60,7 +60,7 @@ class UserTest extends AbstractTest
$this->assertResponseStatusCodeSame(201);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/api/contexts/UserOutput',
'@context' => '/contexts/UserOutput',
'@type' => 'User',
'username' => self::USER_CREATE,
'enabled' => true,