Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8653048
modificados tests
Jun 12, 2025
476fff1
modificados tests
Jun 12, 2025
61a3e02
modificados tests
Jun 12, 2025
7682870
modificados tests
Jun 12, 2025
d3cf343
modificados tests
Jun 12, 2025
5683354
modificados tests
Jun 12, 2025
ffc3b33
modificados tests
Jun 12, 2025
3b9682a
feat: added trait and basic test
abdedarghal111 Jun 12, 2025
26878e0
Merge remote-tracking branch 'origin/test_api' into test_api
abdedarghal111 Jun 12, 2025
b25e426
feat: added comunication methods to trait
abdedarghal111 Jun 13, 2025
ed835a8
Añadido test para insertar datos
Jun 13, 2025
8410d80
merge: solved conflicts
abdedarghal111 Jun 13, 2025
29d778a
chore: rename test
abdedarghal111 Jun 13, 2025
fe94eb4
merge: solved conflicts
abdedarghal111 Jun 13, 2025
3159e3a
conflictos solucionados
Jun 13, 2025
48676f6
fix: fixed info packaging
abdedarghal111 Jun 13, 2025
be0d07b
Merge remote-tracking branch 'refs/remotes/origin/test_api' into test…
Jun 13, 2025
57b4637
Añadido test para DELETE
Jun 13, 2025
816f665
Añadido test para actualizar datos
Jun 13, 2025
e73a87a
Modificado el orden de los tests para eliminar los elementos creados …
Jun 13, 2025
24b37a5
fix: fixed empty database
abdedarghal111 Jun 13, 2025
bf178e3
merge: solved conflicts
abdedarghal111 Jun 13, 2025
57361d0
merge: solved conflicts
abdedarghal111 Jun 13, 2025
c56e128
Añadidos test para los filtros de la API
Jun 16, 2025
b7aa208
Merge remote-tracking branch 'refs/remotes/origin/test_api' into test…
Jun 16, 2025
452dca9
Añadidos los tests de paginacion
Jun 16, 2025
0087d6c
test: added security tests
abdedarghal111 Jun 16, 2025
51debb4
merge: solved conflicts
abdedarghal111 Jun 16, 2025
40c0fdf
Añadidas las funciones para iniciar y detener el servidor a los archi…
Jun 16, 2025
cbf81d5
merge: solved conflicts
abdedarghal111 Jun 16, 2025
09dc823
test: added full security tests
abdedarghal111 Jun 17, 2025
97fb2d7
test: removed unnecesary imports
abdedarghal111 Jun 17, 2025
a1736f1
test: removed comments
abdedarghal111 Jun 17, 2025
de4d040
test: added cache cleaning
abdedarghal111 Jun 17, 2025
d70cf58
Realizados pequeños cambios en las respuestas que se esperan
Jun 17, 2025
97bdeed
Merge remote-tracking branch 'refs/remotes/origin/test_api' into test…
Jun 17, 2025
0cb6561
modificado la funcion testFilterData
Jun 17, 2025
d8167af
merge: solved conflicts
abdedarghal111 Jun 17, 2025
6da0159
fix: patch to non banning after 5th attemp
abdedarghal111 Jun 17, 2025
855d144
feat: added api access modification and creation shortcut
abdedarghal111 Jun 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: PHPUnit Tests

on:
push:
branches: [ master, main ]
branches: [ master, main, test_api ]
pull_request:
branches: [ master, main ]
branches: [ master, main, test_api ]

env:
DB_NAME: facturascripts_test
Expand Down Expand Up @@ -161,6 +161,31 @@ jobs:
EOF
fi

- name: Add api to file
run: |
echo "define('FS_API_KEY', 'prueba');" >> config.php
- name: Start PHP built-in server
run: |
php -S 127.0.0.1:8000 -t . &
sleep 2

- name: Seed database
run: |
if [ "${{ matrix.database.type }}" = "mysql" ] || [ "${{ matrix.database.type }}" = "mariadb" ]; then
mysql --host=${{ env.DB_HOST }} --user=${{ env.DB_USER }} --password=${{ env.DB_PASS }} ${{ env.DB_NAME }} < seed.sql
else
PGPASSWORD=${{ env.DB_PASS }} psql -h ${{ env.DB_HOST }} -U ${{ env.DB_USER }} -d ${{ env.DB_NAME }} -f seed.sql
fi

- name: Run PHPUnit API tests
run: |
if [ -f phpunit-api.xml ] || [ -f phpunit-api.xml.dist ]; then
vendor/bin/phpunit --configuration phpunit-api.xml --coverage-text --coverage-clover=coverage.xml
else
echo "No PHPUnit configuration found. Running with default settings..."
vendor/bin/phpunit --bootstrap vendor/autoload.php tests/
fi

- name: Run PHPUnit tests
run: |
if [ -f phpunit.xml ] || [ -f phpunit.xml.dist ]; then
Expand Down
20 changes: 20 additions & 0 deletions Core/Model/ApiAccess.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,26 @@ public static function primaryColumn(): string
return 'id';
}

/**
* Update HTTP method permissions for this API resource and save the changes.
*
* @param bool $get Whether GET is allowed.
* @param bool $post Whether POST is allowed.
* @param bool $put Whether PUT is allowed.
* @param bool $delete Whether DELETE is allowed.
*
* @return bool True if saved successfully, false otherwise.
*/
public function setAllowed(bool $get, bool $post, bool $put, bool $delete): bool
{
$this->allowget = $get;
$this->allowpost = $post;
$this->allowput = $put;
$this->allowdelete = $delete;

return $this->save();
}

public static function tableName(): string
{
return 'api_access';
Expand Down
59 changes: 59 additions & 0 deletions Core/Model/ApiKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

namespace FacturaScripts\Core\Model;

use FacturaScripts\Core\Base\DataBase\DataBaseWhere;
use FacturaScripts\Core\Tools;
use FacturaScripts\Dinamic\Model\ApiAccess;

/**
* ApiKey model to manage the connection tokens through the api
Expand Down Expand Up @@ -53,6 +55,38 @@ class ApiKey extends Base\ModelClass
/** @var string */
public $nick;

/**
* Adds a new API access entry for the given resource with the specified permissions.
*
* If the resource already exists for this API key, no changes are made.
*
* @param string $resource Resource name to grant access to.
* @param bool $state Initial permission state (applied to all methods).
*
* @return bool True if created or already exists, false on failure.
*/
public function addResourceAccess(string $resource, bool $state = false): bool
{
if (false !== $this->getResourceAccess($resource)) {
return true; // already exists
}

$apiAccess = new ApiAccess();

$apiAccess->idapikey = $this->id;
$apiAccess->resource = $resource;
$apiAccess->allowdelete = $state;
$apiAccess->allowget = $state;
$apiAccess->allowpost = $state;
$apiAccess->allowput = $state;

if (false === $apiAccess->save()) {
return false;
}

return true;
}

public function clear()
{
parent::clear();
Expand All @@ -62,6 +96,31 @@ public function clear()
$this->fullaccess = false;
}

/**
* Retrieves the API access entry for the specified resource.
*
* Use addResourceAccess() first if the resource does not exist.
*
* @param string $resource Resource name to look up.
*
* @return ApiAccess|bool The ApiAccess object if found, false otherwise.
*/
public function getResourceAccess(string $resource): ApiAccess|bool
{
$apiAccess = new ApiAccess();

$where = [
new DataBaseWhere('idapikey', $this->id),
new DataBaseWhere('resource', $resource)
];

if ($apiAccess->loadFromCode('', $where)) {
return $apiAccess;
} else {
return false;
}
}

public static function primaryColumn(): string
{
return 'id';
Expand Down
2 changes: 1 addition & 1 deletion Core/Template/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ private function clientHasManyIncidents(): bool
$ipCount++;
}
}
return $ipCount > self::MAX_INCIDENT_COUNT;
return $ipCount >= self::MAX_INCIDENT_COUNT;
}

private function getIpList(): array
Expand Down
99 changes: 99 additions & 0 deletions Test/API/CRUDTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php
namespace FacturaScripts\Test\API;

use FacturaScripts\Test\Traits\ApiTrait;
use FacturaScripts\Test\Traits\LogErrorsTrait;
use PHPUnit\Framework\TestCase;

class CRUDTest extends TestCase
{

use ApiTrait;
use LogErrorsTrait;

protected function setUp(): void
{
$this->startAPIServer();
}

public function testListResources()
{

$result = $this->makeGETCurl();

$expected = [ 'resources' => $this->getResourcesList() ];

$this->assertEquals($expected, $result, 'response-not-equal');

}

public function testCreateData(){
$form = [
'coddivisa' => '123',
'descripcion' => 'Divisa 123',
];


$result = $this->makePOSTCurl("divisas", $form);


$expected = [
'ok' => 'Registro actualizado correctamente.',
'data' => [
'coddivisa' => '123',
'codiso' => null,
'descripcion' => 'Divisa 123',
'simbolo' => '?',
'tasaconv' => 1,
'tasaconvcompra' => 1
]
];


$this->assertEquals($expected, $result, 'response-not-equal');
}


public function testUpdateData(){
$result = $this->makePUTCurl("divisas/123", [
'descripcion' => 'Divisa 123 Actualizada'
]);
$expected = [
'ok' => 'Registro actualizado correctamente.',
'data' => [
'coddivisa' => '123',
'codiso' => null,
'descripcion' => 'Divisa 123 Actualizada',
'simbolo' => '?',
'tasaconv' => 1,
'tasaconvcompra' => 1
]
];
$this->assertEquals($expected, $result, 'response-not-equal');
}

public function testDeleteData()
{
$result = $this->makeDELETECurl("divisas/123");

$expected = [
'ok' => 'Registro eliminado correctamente!',
'data' => [
'coddivisa' => '123',
'codiso' => null,
'descripcion' => 'Divisa 123 Actualizada',
'simbolo' => '?',
'tasaconv' => 1,
'tasaconvcompra' => 1
]
];

$this->assertEquals($expected, $result, 'response-not-equal');
}

protected function tearDown(): void
{
$this->stopAPIServer();
$this->logErrors();
}
}
Loading
Loading