Skip to content

Commit

Permalink
start to fix tests
Browse files Browse the repository at this point in the history
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
  • Loading branch information
julien-nc committed Sep 10, 2024
1 parent d85348f commit ca0e102
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 232 deletions.
28 changes: 14 additions & 14 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
composer i
- name: Perform PhpUnit tests with coverage
if: ${{ matrix.databases == 'sqlite' && matrix.php-versions == '8.0' && matrix.server-versions == 'master' }}
if: ${{ matrix.databases == 'sqlite' && matrix.php-versions == '8.3' && matrix.server-versions == 'master' }}
run: |
mkdir /tmp/coverage
cd /tmp
Expand All @@ -117,21 +117,21 @@ jobs:
anybadge -l coverage -v `cat /tmp/coverage/cov.value.txt` -m "%.2f%%" -f /tmp/coverage/coverage.svg 50=red 70=orange 80=yellow 90=green
- name: Perform PhpUnit tests
if: ${{ !(matrix.databases == 'sqlite' && matrix.php-versions == '8.0' && matrix.server-versions == 'master') }}
if: ${{ !(matrix.databases == 'sqlite' && matrix.php-versions == '8.3' && matrix.server-versions == 'master') }}
run: |
~/html/nextcloud/apps/${{ env.APP_ID }}/vendor/bin/phpunit --configuration ~/html/nextcloud/apps/${{ env.APP_ID }}/tests/phpunit.xml && SUCCESS=yes || SUCCESS=no
if [ $SUCCESS = "yes" ]; then echo "TESTS PASSED"; else echo "TESTS FAILED"; exit 1; fi
- name: Upload coverage
if: ${{ github.ref == 'refs/heads/master' && matrix.databases == 'sqlite' && matrix.php-versions == '8.0' && matrix.server-versions == 'master' }}
uses: actions/upload-artifact@v2
with:
name: coverage
path: /tmp/coverage
#- name: Upload coverage
# if: ${{ github.ref == 'refs/heads/master' && matrix.databases == 'sqlite' && matrix.php-versions == '8.0' && matrix.server-versions == 'master' }}
# uses: actions/upload-artifact@v2
# with:
# name: coverage
# path: /tmp/coverage

- name: Deploy
if: ${{ github.ref == 'refs/heads/master' && matrix.databases == 'sqlite' && matrix.php-versions == '8.0' && matrix.server-versions == 'master' }}
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: /tmp/coverage
#- name: Deploy
# if: ${{ github.ref == 'refs/heads/master' && matrix.databases == 'sqlite' && matrix.php-versions == '8.0' && matrix.server-versions == 'master' }}
# uses: peaceiris/actions-gh-pages@v3
# with:
# github_token: ${{ secrets.GITHUB_TOKEN }}
# publish_dir: /tmp/coverage
21 changes: 16 additions & 5 deletions lib/Controller/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use OCA\Cospend\Attribute\SupportFederatedProject;
use OCA\Cospend\Attribute\CospendUserPermissions;
use OCA\Cospend\Db\BillMapper;
use OCA\Cospend\Db\ProjectMapper;
use OCA\Cospend\Exception\CospendBasicException;
use OCA\Cospend\ResponseDefinitions;
use OCA\Cospend\Service\CospendService;
Expand Down Expand Up @@ -70,6 +71,7 @@ public function __construct(
private IManager $shareManager,
private IL10N $trans,
private BillMapper $billMapper,
private ProjectMapper $projectMapper,
private LocalProjectService $localProjectService,
private CospendService $cospendService,
private ActivityManager $activityManager,
Expand All @@ -96,21 +98,30 @@ private static function getResponseFromClientException(ClientException $e): Data
* @param string $id
* @param string $name
* @return DataResponse<Http::STATUS_OK, CospendFullProjectInfo, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array<string, string>, array{}>

Check failure on line 100 in lib/Controller/ApiController.php

View workflow job for this annotation

GitHub Actions / Psalm check

InvalidReturnType

lib/Controller/ApiController.php:100:13: InvalidReturnType: The declared return type 'OCP\AppFramework\Http\DataResponse<200|400, array<string, array<array-key, array<array-key, array{accesslevel?: 0|1|2|3|4, b?: int, circleid?: string, g?: int, groupid?: string, id?: int, label?: null|string, manually_added?: bool, name?: string, password?: null|string, r?: int, token?: string, type?: 'c'|'g'|'l'|'u', userid?: string}|null|scalar>|float>|null|scalar>, array<never, never>>' for OCA\Cospend\Controller\ApiController::createProject is incorrect, got 'OCP\AppFramework\Http\DataResponse<400, string, array<never, never>>|OCP\AppFramework\Http\DataResponse<int, array<array-key, mixed>, array<never, never>>' (see https://psalm.dev/011)
* @throws DoesNotExistException
* @throws Exception
* @throws MultipleObjectsReturnedException
*
* 200: Project successfully created
* 400: Failed to create project
*/
#[NoAdminRequired]
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT, tags: ['Projects'])]
public function createProject(string $id, string $name): DataResponse {
$result = $this->localProjectService->createProject($name, $id, null, $this->userId);
if (isset($result['id'])) {
$projInfo = $this->localProjectService->getProjectInfo($result['id']);
try {
$this->projectMapper->getById($id);
return new DataResponse('project already exists', Http::STATUS_BAD_REQUEST);

Check failure on line 113 in lib/Controller/ApiController.php

View workflow job for this annotation

GitHub Actions / Psalm check

InvalidReturnStatement

lib/Controller/ApiController.php:113:11: InvalidReturnStatement: The inferred type 'OCP\AppFramework\Http\DataResponse<400, 'project already exists', array<never, never>>' does not match the declared return type 'OCP\AppFramework\Http\DataResponse<200|400, array<string, array<array-key, array<array-key, array{accesslevel?: 0|1|2|3|4, b?: int, circleid?: string, g?: int, groupid?: string, id?: int, label?: null|string, manually_added?: bool, name?: string, password?: null|string, r?: int, token?: string, type?: 'c'|'g'|'l'|'u', userid?: string}|null|scalar>|float>|null|scalar>, array<never, never>>' for OCA\Cospend\Controller\ApiController::createProject (see https://psalm.dev/128)
} catch (DoesNotExistException $e) {
}
try {
$jsonProject = $this->localProjectService->createProject($name, $id, null, $this->userId);
$projInfo = $this->localProjectService->getProjectInfo($jsonProject['id']);
$projInfo['myaccesslevel'] = Application::ACCESS_LEVEL_ADMIN;
return new DataResponse($projInfo);
} else {
return new DataResponse($result, Http::STATUS_BAD_REQUEST);
} catch (CospendBasicException $e) {
return new DataResponse($e->data, $e->getCode());

Check failure on line 122 in lib/Controller/ApiController.php

View workflow job for this annotation

GitHub Actions / Psalm check

LessSpecificReturnStatement

lib/Controller/ApiController.php:122:11: LessSpecificReturnStatement: The type 'OCP\AppFramework\Http\DataResponse<int, array<array-key, mixed>, array<never, never>>' is more general than the declared return type 'OCP\AppFramework\Http\DataResponse<200|400, array<string, array<array-key, array<array-key, array{accesslevel?: 0|1|2|3|4, b?: int, circleid?: string, g?: int, groupid?: string, id?: int, label?: null|string, manually_added?: bool, name?: string, password?: null|string, r?: int, token?: string, type?: 'c'|'g'|'l'|'u', userid?: string}|null|scalar>|float>|null|scalar>, array<never, never>>' for OCA\Cospend\Controller\ApiController::createProject (see https://psalm.dev/129)
} catch (Exception $e) {
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);

Check failure on line 124 in lib/Controller/ApiController.php

View workflow job for this annotation

GitHub Actions / Psalm check

InvalidReturnStatement

lib/Controller/ApiController.php:124:11: InvalidReturnStatement: The inferred type 'OCP\AppFramework\Http\DataResponse<400, string, array<never, never>>' does not match the declared return type 'OCP\AppFramework\Http\DataResponse<200|400, array<string, array<array-key, array<array-key, array{accesslevel?: 0|1|2|3|4, b?: int, circleid?: string, g?: int, groupid?: string, id?: int, label?: null|string, manually_added?: bool, name?: string, password?: null|string, r?: int, token?: string, type?: 'c'|'g'|'l'|'u', userid?: string}|null|scalar>|float>|null|scalar>, array<never, never>>' for OCA\Cospend\Controller\ApiController::createProject (see https://psalm.dev/128)
}
}

Expand Down
22 changes: 17 additions & 5 deletions lib/Controller/OldApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
use OCA\Cospend\Attribute\CospendPublicAuth;
use OCA\Cospend\Attribute\CospendUserPermissions;
use OCA\Cospend\Db\BillMapper;
use OCA\Cospend\Db\ProjectMapper;
use OCA\Cospend\Exception\CospendBasicException;
use OCA\Cospend\Service\LocalProjectService;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\BruteForceProtection;

Expand All @@ -46,6 +48,7 @@ public function __construct(
IRequest $request,
private IL10N $trans,
private BillMapper $billMapper,
private ProjectMapper $projectMapper,
private LocalProjectService $localProjectService,
private ActivityManager $activityManager,
public ?string $userId,
Expand Down Expand Up @@ -98,11 +101,20 @@ public function apiPrivSetProjectInfo(string $projectId, ?string $name = null, ?
#[CORS]
#[NoCSRFRequired]
public function apiPrivCreateProject(string $name, string $id, ?string $contact_email = null): DataResponse {
$result = $this->localProjectService->createProject($name, $id, $contact_email, $this->userId);
if (isset($result['id'])) {
return new DataResponse($result['id']);
} else {
return new DataResponse($result, Http::STATUS_BAD_REQUEST);
try {
$this->projectMapper->getById($id);
return new DataResponse('project already exists', Http::STATUS_BAD_REQUEST);
} catch (DoesNotExistException $e) {
}
try {
$jsonProject = $this->localProjectService->createProject($name, $id, $contact_email, $this->userId);
$projInfo = $this->localProjectService->getProjectInfo($jsonProject['id']);
$projInfo['myaccesslevel'] = Application::ACCESS_LEVEL_ADMIN;
return new DataResponse($projInfo);
} catch (CospendBasicException $e) {
return new DataResponse($e->data, $e->getCode());
} catch (Exception $e) {
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);
}
}

Expand Down
129 changes: 52 additions & 77 deletions lib/Db/ProjectMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
namespace OCA\Cospend\Db;

use DateTime;
use OCA\Cospend\Exception\CospendBasicException;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\AppFramework\Db\QBMapper;
use OCP\AppFramework\Http;
use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
Expand All @@ -25,16 +27,16 @@
* @extends QBMapper<Project>
*/
class ProjectMapper extends QBMapper {
public const TABLE_NAME = 'cospend_projects';

public const ARCHIVED_TS_UNSET = -1;
public const ARCHIVED_TS_NOW = 0;

public function __construct(
IDBConnection $db,
private IL10N $l10n,
private CategoryMapper $categoryMapper,
private PaymentModeMapper $paymentModeMapper,
) {
parent::__construct($db, self::TABLE_NAME, Project::class);
parent::__construct($db, 'cospend_projects', Project::class);
}

/**
Expand All @@ -54,88 +56,61 @@ public function getById(string $projectId): Project {
return $this->findEntity($qb);
}

/**
* @param string $name
* @param string $id
* @param string|null $contact_email
* @param array $defaultCategories
* @param array $defaultPaymentModes
* @param string $userid
* @param bool $createDefaultCategories
* @param bool $createDefaultPaymentModes
* @return Project
* @throws CospendBasicException
* @throws Exception
*/
public function createProject(
string $name, string $id, ?string $contact_email, array $defaultCategories, array $defaultPaymentModes,
string $userid = '', bool $createDefaultCategories = true, bool $createDefaultPaymentModes = true
): array {
$qb = $this->db->getQueryBuilder();

$qb->select('id')
->from($this->getTableName(), 'p')
->where(
$qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_STR))
);
$req = $qb->executeQuery();

$dbId = null;
while ($row = $req->fetch()) {
$dbId = $row['id'];
break;
): Project {
// check if id is valid
if (str_contains($id, '/')) {
throw new CospendBasicException('', Http::STATUS_BAD_REQUEST, ['message' => $this->l10n->t('Invalid project id')]);
}
$req->closeCursor();
$qb = $this->db->getQueryBuilder();
if ($dbId === null) {
// check if id is valid
if (strpos($id, '/') !== false) {
return ['message' => $this->l10n->t('Invalid project id')];
}
if ($contact_email === null) {
$contact_email = '';
}
$ts = (new DateTime())->getTimestamp();
$qb->insert($this->getTableName())
->values([
'userid' => $qb->createNamedParameter($userid, IQueryBuilder::PARAM_STR),
'id' => $qb->createNamedParameter($id, IQueryBuilder::PARAM_STR),
'name' => $qb->createNamedParameter($name, IQueryBuilder::PARAM_STR),
'email' => $qb->createNamedParameter($contact_email, IQueryBuilder::PARAM_STR),
'lastchanged' => $qb->createNamedParameter($ts, IQueryBuilder::PARAM_INT)
]);
$qb->executeStatement();
$qb = $this->db->getQueryBuilder();

// create default categories
if ($createDefaultCategories) {
foreach ($defaultCategories as $category) {
$icon = urlencode($category['icon']);
$color = $category['color'];
$name = $category['name'];
$qb->insert('cospend_categories')
->values([
'projectid' => $qb->createNamedParameter($id, IQueryBuilder::PARAM_STR),
'encoded_icon' => $qb->createNamedParameter($icon, IQueryBuilder::PARAM_STR),
'color' => $qb->createNamedParameter($color, IQueryBuilder::PARAM_STR),
'name' => $qb->createNamedParameter($name, IQueryBuilder::PARAM_STR),
]);
$qb->executeStatement();
$qb = $this->db->getQueryBuilder();
}
}

// create default payment modes
if ($createDefaultPaymentModes) {
foreach ($defaultPaymentModes as $pm) {
$icon = urlencode($pm['icon']);
$color = $pm['color'];
$name = $pm['name'];
$oldId = $pm['old_id'];
$qb->insert('cospend_paymentmodes')
->values([
'projectid' => $qb->createNamedParameter($id, IQueryBuilder::PARAM_STR),
'encoded_icon' => $qb->createNamedParameter($icon, IQueryBuilder::PARAM_STR),
'color' => $qb->createNamedParameter($color, IQueryBuilder::PARAM_STR),
'name' => $qb->createNamedParameter($name, IQueryBuilder::PARAM_STR),
'old_id' => $qb->createNamedParameter($oldId, IQueryBuilder::PARAM_STR),
]);
$qb->executeStatement();
$qb = $this->db->getQueryBuilder();
}
$ts = (new DateTime())->getTimestamp();
$project = new Project();
$project->setUserid($userid);
$project->setId($id);
$project->setName($name);
$project->setEmail($contact_email === null ? '' : $contact_email);
$project->setLastchanged($ts);
$insertedProject = $this->insert($project);

if ($createDefaultCategories) {
foreach ($defaultCategories as $defaultCategory) {
$category = new Category();
$category->setProjectid($insertedProject->getId());
$category->setName($defaultCategory['name']);
$category->setColor($defaultCategory['color']);
$category->setEncodedIcon(urlencode($defaultCategory['icon']));
$this->categoryMapper->insert($category);
}
}

return ['id' => $id];
} else {
return ['message' => $this->l10n->t('A project with id "%1$s" already exists', [$id])];
if ($createDefaultPaymentModes) {
foreach ($defaultPaymentModes as $defaultPm) {
$paymentMode = new PaymentMode();
$paymentMode->setProjectid($insertedProject->getId());
$paymentMode->setName($defaultPm['name']);
$paymentMode->setColor($defaultPm['color']);
$paymentMode->setEncodedIcon(urlencode($defaultPm['icon']));
$paymentMode->setOldId($defaultPm['old_id']);
$this->paymentModeMapper->insert($paymentMode);
}
}

return $insertedProject;
}

/**
Expand Down
8 changes: 7 additions & 1 deletion lib/Service/LocalProjectService.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,18 @@ public function getShareAccessLevel(string $projectId, int $shId): int {
* @param bool $createDefaultCategories
* @param bool $createDefaultPaymentModes
* @return array
* @throws CospendBasicException
* @throws \OCP\DB\Exception
*/
public function createProject(
string $name, string $id, ?string $contact_email, string $userId = '',
bool $createDefaultCategories = true, bool $createDefaultPaymentModes = true
): array {
return $this->projectMapper->createProject(
$newProject = $this->projectMapper->createProject(
$name, $id, $contact_email, $this->defaultCategories, $this->defaultPaymentModes,
$userId, $createDefaultCategories, $createDefaultPaymentModes
);
return $newProject->jsonSerialize();
}

public function deleteProject(string $projectId): void {
Expand Down Expand Up @@ -318,6 +321,9 @@ public function deleteProject(string $projectId): void {
*
* @param string $projectId
* @return CospendProjectInfoPlusExtra|null
* @throws CospendBasicException
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws \OCP\DB\Exception
*/
public function getProjectInfo(string $projectId): ?array {
Expand Down
2 changes: 1 addition & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1040,7 +1040,7 @@ export default {
console.error(error)
showError(
t('cospend', 'Failed to create project')
+ ': ' + (error.response?.data?.ocs?.meta?.message || error.response?.data?.ocs?.data?.message || error.response?.request?.responseText),
+ ': ' + error.response?.data?.ocs?.data,
)
})
},
Expand Down
Loading

0 comments on commit ca0e102

Please sign in to comment.