Skip to content

Commit 668e892

Browse files
committed
Add support for file question
Signed-off-by: Konstantin Myakshin <[email protected]>
1 parent b15eda0 commit 668e892

19 files changed

+1080
-91
lines changed

appinfo/info.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
- **🙋 Get involved!** We have lots of stuff planned like more question types, collaboration on forms, [and much more](https://github.com/nextcloud/forms/milestones)!
1414
]]></description>
1515

16-
<version>4.2.3</version>
16+
<version>4.2.4</version>
1717
<licence>agpl</licence>
1818

1919
<author>Affan Hussain</author>
@@ -54,6 +54,10 @@
5454
<nextcloud min-version="28" max-version="29" />
5555
</dependencies>
5656

57+
<background-jobs>
58+
<job>OCA\Forms\BackgroundJob\CleanupUploadedFilesJob</job>
59+
</background-jobs>
60+
5761
<settings>
5862
<admin>OCA\Forms\Settings\Settings</admin>
5963
<admin-section>OCA\Forms\Settings\SettingsSection</admin-section>

appinfo/routes.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,14 @@
331331
'apiVersion' => 'v2(\.[1-4])?'
332332
]
333333
],
334+
[
335+
'name' => 'api#uploadFiles',
336+
'url' => '/api/{apiVersion}/uploadFiles/{formId}/{questionId}',
337+
'verb' => 'POST',
338+
'requirements' => [
339+
'apiVersion' => 'v2.5'
340+
]
341+
],
334342
[
335343
'name' => 'api#insertSubmission',
336344
'url' => '/api/{apiVersion}/submission/insert',
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace OCA\Forms\BackgroundJob;
4+
5+
use OCA\Forms\Db\FormMapper;
6+
use OCA\Forms\Db\UploadedFileMapper;
7+
use OCP\AppFramework\Utility\ITimeFactory;
8+
use OCP\BackgroundJob\TimedJob;
9+
use OCP\Files\IRootFolder;
10+
use Psr\Log\LoggerInterface;
11+
12+
class CleanupUploadedFilesJob extends TimedJob {
13+
private const FILE_LIFETIME = '-2 days';
14+
15+
public function __construct(
16+
private IRootFolder $storage,
17+
private FormMapper $formMapper,
18+
private UploadedFileMapper $uploadedFileMapper,
19+
private LoggerInterface $logger,
20+
ITimeFactory $time) {
21+
parent::__construct($time);
22+
23+
$this->setInterval(60 * 60 * 24);
24+
25+
}
26+
27+
/**
28+
* @param array $argument
29+
*/
30+
public function run($argument): void {
31+
$dateTime = new \DateTimeImmutable(self::FILE_LIFETIME);
32+
$this->logger->info('Deleting files that were uploaded before {before} and still not submitted.', [
33+
'before' => $dateTime->format(\DateTimeImmutable::ATOM),
34+
]);
35+
36+
$uploadedFiles = $this->uploadedFileMapper->findUploadedEarlierThan($dateTime);
37+
38+
$deleted = 0;
39+
foreach ($uploadedFiles as $uploadedFile) {
40+
$this->logger->info('Deleting uploaded file "{originalFileName}" for form {formId}.', [
41+
'originalFileName' => $uploadedFile->getOriginalFileName(),
42+
'formId' => $uploadedFile->getFormId(),
43+
]);
44+
45+
$form = $this->formMapper->findById($uploadedFile->getFormId());
46+
$userFolder = $this->storage->getUserFolder($form->getOwnerId());
47+
48+
$nodes = $userFolder->getById($uploadedFile->getFileId());
49+
50+
if (!empty($nodes)) {
51+
$node = $nodes[0];
52+
$node->delete();
53+
} else {
54+
$this->logger->warning('Could not find uploaded file "{fileId}" for deletion.', [
55+
'fileId' => $uploadedFile->getFileId(),
56+
]);
57+
}
58+
59+
$this->uploadedFileMapper->delete($uploadedFile);
60+
61+
$deleted++;
62+
}
63+
64+
$this->logger->info('Deleted {deleted} uploaded files.', ['deleted' => $deleted]);
65+
}
66+
}

lib/Constants.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class Constants {
9191
public const ANSWER_TYPE_DATE = 'date';
9292
public const ANSWER_TYPE_DATETIME = 'datetime';
9393
public const ANSWER_TYPE_TIME = 'time';
94+
public const ANSWER_TYPE_FILE = 'file';
9495

9596
// All AnswerTypes
9697
public const ANSWER_TYPES = [
@@ -101,7 +102,8 @@ class Constants {
101102
self::ANSWER_TYPE_LONG,
102103
self::ANSWER_TYPE_DATE,
103104
self::ANSWER_TYPE_DATETIME,
104-
self::ANSWER_TYPE_TIME
105+
self::ANSWER_TYPE_TIME,
106+
self::ANSWER_TYPE_FILE,
105107
];
106108

107109
// AnswerTypes, that need/have predefined Options
@@ -155,6 +157,21 @@ class Constants {
155157
'validationRegex' => ['string'],
156158
];
157159

160+
public const EXTRA_SETTINGS_FILE = [
161+
'allowedFileTypes',
162+
'allowedFileExtensions',
163+
'maxAllowedFilesCount',
164+
'maxFileSize',
165+
];
166+
167+
// should be in sync with FileTypes.js
168+
public const EXTRA_SETTINGS_ALLOWED_FILE_TYPES = [
169+
'image',
170+
'x-office/document',
171+
'x-office/presentation',
172+
'x-office/spreadsheet',
173+
];
174+
158175
/**
159176
* !! Keep in sync with src/mixins/ShareTypes.js !!
160177
*/
@@ -204,4 +221,8 @@ class Constants {
204221
];
205222

206223
public const DEFAULT_FILE_FORMAT = 'csv';
224+
225+
public const UNSUBMITTED_FILES_FOLDER = 'forms/unsubmitted';
226+
227+
public const FILES_FOLDER = 'forms';
207228
}

0 commit comments

Comments
 (0)