diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3f77d1cc..5aa3a196 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -91,6 +91,11 @@ jobs:
- name: PHP & Vue Unit Tests
run: |
+ mkdir -p server/apps/integration_openproject
+ cp -r `ls -A | grep -v 'server'` server/apps/integration_openproject/
+ cd server
+ ./occ a:e integration_openproject
+ cd apps/integration_openproject
make phpunit
make jsunit
@@ -99,7 +104,7 @@ jobs:
uses: romeovs/lcov-reporter-action@v0.3.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- lcov-file: ./coverage/jest/lcov.info
+ lcov-file: ./server/apps/integration_openproject/coverage/jest/lcov.info
delete-old-comments: true
title: "JS Code Coverage"
@@ -107,8 +112,8 @@ jobs:
if: ${{ github.event_name == 'pull_request' && matrix.nextcloudVersion == 'master' && matrix.phpVersion == '8.1' }}
uses: danielpalme/ReportGenerator-GitHub-Action@5.0.3
with:
- reports: './coverage/php/cobertura.xml' # REQUIRED # The coverage reports that should be parsed (separated by semicolon). Globbing is supported.
- targetdir: './coverage/php' # REQUIRED # The directory where the generated report should be saved.
+ reports: './server/apps/integration_openproject/coverage/php/cobertura.xml' # REQUIRED # The coverage reports that should be parsed (separated by semicolon). Globbing is supported.
+ targetdir: './server/apps/integration_openproject/coverage/php' # REQUIRED # The directory where the generated report should be saved.
reporttypes: 'lcov' # The output formats and scope (separated by semicolon) Values: Badges, Clover, Cobertura, CsvSummary, Html, HtmlChart, HtmlInline, HtmlInline_AzurePipelines, HtmlInline_AzurePipelines_Dark, HtmlSummary, JsonSummary, Latex, LatexSummary, lcov, MarkdownSummary, MHtml, PngChart, SonarQube, TeamCitySummary, TextSummary, Xml, XmlSummary
sourcedirs: '' # Optional directories which contain the corresponding source code (separated by semicolon). The source directories are used if coverage report contains classes without path information.
historydir: '' # Optional directory for storing persistent coverage information. Can be used in future reports to show coverage evolution.
@@ -127,7 +132,7 @@ jobs:
uses: romeovs/lcov-reporter-action@v0.3.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- lcov-file: ./coverage/php/lcov.info
+ lcov-file: ./server/apps/integration_openproject/coverage/php/lcov.info
delete-old-comments: true
title: "PHP Code Coverage"
@@ -136,14 +141,15 @@ jobs:
uses: VeryGoodOpenSource/very_good_coverage@v1.2.0
with:
min_coverage: '59'
- path: './coverage/jest/lcov.info'
+ path: './server/apps/integration_openproject/coverage/jest/lcov.info'
- name: PHP coverage check
if: ${{ github.event_name == 'pull_request' && matrix.nextcloudVersion == 'master' && matrix.phpVersion == '8.1' }}
uses: VeryGoodOpenSource/very_good_coverage@v1.2.0
with:
min_coverage: '57'
- path: './coverage/php/lcov.info'
+ path: './server/apps/integration_openproject/coverage/php/lcov.info'
+
api-tests:
name: API tests
strategy:
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 41a03dc5..5604ff6c 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -38,7 +38,7 @@ For more information on how to set up and use the OpenProject application, pleas
- OCA\OpenProject\BackgroundJob\CheckNotifications
+ OCA\OpenProject\BackgroundJob\RemoveExpiredDirectUploadTokens
OCA\OpenProject\Settings\Admin
diff --git a/lib/BackgroundJob/RemoveExpiredDirectUploadTokens.php b/lib/BackgroundJob/RemoveExpiredDirectUploadTokens.php
new file mode 100644
index 00000000..60355702
--- /dev/null
+++ b/lib/BackgroundJob/RemoveExpiredDirectUploadTokens.php
@@ -0,0 +1,58 @@
+
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\OpenProject\BackgroundJob;
+
+use OCP\BackgroundJob\TimedJob;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\DB\Exception;
+use Psr\Log\LoggerInterface;
+
+use OCA\OpenProject\Service\DatabaseService;
+
+class RemoveExpiredDirectUploadTokens extends TimedJob {
+
+ /** @var LoggerInterface */
+ protected LoggerInterface $logger;
+
+ /** @var DatabaseService */
+ protected DatabaseService $databaseService;
+
+ public function __construct(ITimeFactory $time, DatabaseService $databaseService, LoggerInterface $logger) {
+ parent::__construct($time);
+ // runs once a day
+ $this->setInterval(24 * 3600);
+ $this->databaseService = $databaseService;
+ $this->logger = $logger;
+ }
+
+ /**
+ * @param mixed $argument
+ * @return void
+ * @throws Exception
+ */
+ public function run($argument): void {
+ $this->databaseService->deleteExpiredTokens();
+ $this->logger->info('Deleted all the expired tokens from Database');
+ }
+}
diff --git a/lib/Service/DatabaseService.php b/lib/Service/DatabaseService.php
index d6a474c3..393f7d55 100644
--- a/lib/Service/DatabaseService.php
+++ b/lib/Service/DatabaseService.php
@@ -31,7 +31,7 @@ class DatabaseService {
/**
* @var IDBConnection
*/
- private IDBConnection $db;
+ public IDBConnection $db;
/** @var string table name */
@@ -102,6 +102,19 @@ class DatabaseService {
];
}
+ /**
+ *
+ * @throws Exception
+ */
+ public function deleteExpiredTokens(): void {
+ $query = $this->db->getQueryBuilder();
+ $query->delete($this->table)
+ ->where(
+ $query->expr()->lt('expires_on', $query->createNamedParameter(time()))
+ );
+ $query->execute();
+ }
+
/**
* deletes the token from the table
* @param string $token
diff --git a/tests/lib/Service/DatabaseServiceTest.php b/tests/lib/Service/DatabaseServiceTest.php
new file mode 100644
index 00000000..bdd264de
--- /dev/null
+++ b/tests/lib/Service/DatabaseServiceTest.php
@@ -0,0 +1,194 @@
+
+ *
+ * @author Your name
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\OpenProject\Service;
+
+use OCA\OpenProject\AppInfo\Application;
+use OCP\DB\Exception;
+use PHPUnit\Framework\TestCase;
+
+class DatabaseServiceTest extends TestCase {
+ /**
+ * @var DatabaseService
+ */
+ private $databaseService;
+ private const TABLE_NAME = 'direct_upload';
+
+ /**
+ * createdAt and expiresOn info is not included since it requires current timestamp
+ *
+ * @var array
+ */
+ private array $unexpiredDirectUploadInfo = [
+ [
+ "token" => 'unExpiredToken1',
+ "folderId" => 1,
+ "userId" => 'u1',
+ ],
+ [
+ "token" => 'unExpiredToken2',
+ "folderId" => 1,
+ "userId" => 'u1',
+ ],
+ [
+ "token" => 'unExpiredToken3',
+ "folderId" => 1,
+ "userId" => 'u1',
+ ],
+
+ ];
+
+ /**
+ * createdAt and expiresOn info is not included since it requires current timestamp
+ *
+ * @var array
+ */
+ private array $expiredDirectUploadInfo = [
+ [
+ "token" => 'expiredToken1',
+ "folderId" => 1,
+ "userId" => 'u1',
+ ],
+ [
+ "token" => 'expiredToken2',
+ "folderId" => 1,
+ "userId" => 'u1',
+ ],
+ [
+ "token" => 'expiredToken3',
+ "folderId" => 1,
+ "userId" => 'u1',
+ ],
+
+ ];
+
+ protected function setUp(): void {
+ $app = new Application();
+ $c = $app->getContainer();
+
+ /** @var DatabaseService $databaseService */
+ $databaseService = $c->get(DatabaseService::class);
+ $this->databaseService = $databaseService;
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function tearDown(): void {
+ $query = $this->databaseService->db->getQueryBuilder();
+ $query->delete(self::TABLE_NAME);
+ $query->execute();
+ }
+
+ /**
+ * @throws Exception
+ * @return array
+ */
+ public function getAllTokensFromTable(): array {
+ $tokens = [];
+ $query = $this->databaseService->db->getQueryBuilder();
+ $query->select('token')
+ ->from(self::TABLE_NAME);
+ $req = $query->executeQuery();
+ while ($row = $req->fetch()) {
+ $tokens[] = $row['token'];
+ }
+ return $tokens;
+ }
+
+
+ /**
+ * @return void
+ *
+ * @throws Exception
+ */
+ public function testDeleteSingleExpiredToken(): void {
+ $this->databaseService->setInfoForDirectUpload("expiredToken", 1, "u1", time(), time() - 1000);
+ $this->databaseService->deleteExpiredTokens();
+ $token = $this->getAllTokensFromTable();
+ self::assertEquals(0, sizeof($token));
+ }
+
+ /**
+ * @return void
+ *
+ * @throws Exception
+ */
+ public function testDeleteMultipleExpiredTokens(): void {
+ foreach ($this->expiredDirectUploadInfo as $info) {
+ $this->databaseService->setInfoForDirectUpload($info['token'], $info['folderId'], $info['userId'], time(), time() - 1000);
+ }
+ $this->databaseService->deleteExpiredTokens();
+ $tokens = $this->getAllTokensFromTable();
+ self::assertEquals(0, sizeof($tokens));
+ }
+
+ /**
+ * @return void
+ *
+ * @throws Exception
+ */
+ public function testDeleteSingleUnExpiredToken(): void {
+ $this->databaseService->setInfoForDirectUpload("unExpiredToken", 1, "u1", time(), time() + 1000);
+ $this->databaseService->deleteExpiredTokens();
+ $token = $this->getAllTokensFromTable();
+ self::assertSame('unExpiredToken', $token[0]);
+ }
+
+ /**
+ * @return void
+ *
+ * @throws Exception
+ */
+ public function testDeleteMultipleUnExpiredTokens(): void {
+ foreach ($this->unexpiredDirectUploadInfo as $info) {
+ $this->databaseService->setInfoForDirectUpload($info['token'], $info['folderId'], $info['userId'], time(), time() + 1000);
+ }
+ $this->databaseService->deleteExpiredTokens();
+ $tokens = $this->getAllTokensFromTable();
+ self::assertEquals(sizeof($this->unexpiredDirectUploadInfo), sizeof($tokens));
+ foreach ($this->unexpiredDirectUploadInfo as $info) {
+ self::assertContains($info['token'], $tokens);
+ }
+ }
+
+ /**
+ * @return void
+ *
+ * @throws Exception
+ */
+ public function testDeleteMultipleExpiredAndUnexpiredTokens(): void {
+ foreach ($this->expiredDirectUploadInfo as $info) {
+ $this->databaseService->setInfoForDirectUpload($info['token'], $info['folderId'], $info['userId'], time(), time() - 1000);
+ }
+ foreach ($this->unexpiredDirectUploadInfo as $info) {
+ $this->databaseService->setInfoForDirectUpload($info['token'], $info['folderId'], $info['userId'], time(), time() + 1000);
+ }
+ $this->databaseService->deleteExpiredTokens();
+ $tokens = $this->getAllTokensFromTable();
+ self::assertEquals(sizeof($this->unexpiredDirectUploadInfo), sizeof($tokens));
+ foreach ($this->unexpiredDirectUploadInfo as $info) {
+ self::assertContains($info['token'], $tokens);
+ }
+ }
+}