Skip to content

Commit

Permalink
feat: Implement custom submission message
Browse files Browse the repository at this point in the history
This message is shown when a user submits the form and can be formatted using markdown.

Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux committed Jun 28, 2023
1 parent 1be02c1 commit c797fd2
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 7 deletions.
6 changes: 5 additions & 1 deletion lib/Db/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
* @method void setShowExpiration(bool $value)
* @method integer getLastUpdated()
* @method void setLastUpdated(integer $value)
* @method string getSubmissionMessage()
* @method void setSubmissionMessage(string $value)
*/
class Form extends Entity {
protected $hash;
Expand All @@ -64,6 +66,7 @@ class Form extends Entity {
protected $isAnonymous;
protected $submitMultiple;
protected $showExpiration;
protected $submissionMessage;
protected $lastUpdated;

/**
Expand Down Expand Up @@ -102,7 +105,8 @@ public function read() {
'isAnonymous' => (bool)$this->getIsAnonymous(),
'submitMultiple' => (bool)$this->getSubmitMultiple(),
'showExpiration' => (bool)$this->getShowExpiration(),
'lastUpdated' => (int)$this->getLastUpdated()
'lastUpdated' => (int)$this->getLastUpdated(),
'submissionMessage' => $this->getSubmissionMessage() ?? '',
];
}
}
60 changes: 60 additions & 0 deletions lib/Migration/Version030400Date20230628011500.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2023 Ferdinand Thiessen <[email protected]>
*
* @author Ferdinand Thiessen <[email protected]>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Forms\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

class Version030400Date20230628011500 extends SimpleMigrationStep {

/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->getTable('forms_v2_forms');

if (!$table->hasColumn('submission_message')) {
$table->addColumn('submission_message', Types::STRING, [
'notnull' => false,
'default' => '',
'comment' => 'custom thank you message',
]);

return $schema;
}

return null;
}
}
61 changes: 61 additions & 0 deletions src/components/SidebarTabs/SettingsSidebarTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,22 @@
{{ t('forms', 'Show expiration date on form') }}
</NcCheckboxRadioSwitch>
</div>
<div class="submission-message">
<label class="submission-message__label"
:tabindex="editMessage ? null : '0'"
@focus="editMessage = true">
{{ t('forms', 'Custom submission message') }}
<textarea v-if="editMessage || !form.submissionMessage"
v-click-outside="() => { editMessage = false }"
:value="form.submissionMessage"
:placeholder="t('forms', 'Message to show after an user submitted the form (formatting using Markdown is supported)')"
class="submission-message__input"
@blur="editMessage = false"
@change="onSubmissionMessageChange" />
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-else class="submission-message__output" v-html="submissionMessageHTML" />
</label>
</div>
</div>
</template>

Expand All @@ -68,14 +84,22 @@ import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadi
import NcDatetimePicker from '@nextcloud/vue/dist/Components/NcDatetimePicker.js'
import ShareTypes from '../../mixins/ShareTypes.js'
import { directive as ClickOutside } from 'v-click-outside'
export default {
components: {
NcCheckboxRadioSwitch,
NcDatetimePicker,
},
directives: {
ClickOutside,
},
mixins: [ShareTypes],
inject: ['$markdownit'],
props: {
form: {
type: Object,
Expand All @@ -89,6 +113,8 @@ export default {
stringify: this.stringifyDate,
parse: this.parseTimestampToDate,
},
/** If custom submission message is shown as input or rendered markdown */
editMessage: false,
}
},
Expand Down Expand Up @@ -125,6 +151,12 @@ export default {
expirationDate() {
return moment(this.form.expires, 'X').toDate()
},
/**
* The submission message rendered as HTML
*/
submissionMessageHTML() {
return this.$markdownit.render(this.form.submissionMessage || '')
},
},
methods: {
Expand Down Expand Up @@ -159,6 +191,10 @@ export default {
this.$emit('update:formProp', 'expires', parseInt(moment(datetime).format('X')))
},
onSubmissionMessageChange({ target }) {
this.$emit('update:formProp', 'submissionMessage', target.value)
},
/**
* Datepicker timestamp to string
*
Expand Down Expand Up @@ -215,4 +251,29 @@ export default {
.settings-div--indent {
margin-left: 40px;
}
.submission-message {
display: flex;
flex-direction: column;
margin-block-start: 12px;
&__input, &__output {
width: 100%;
min-height: 70px;
}
&__output {
@import '../../scssmixins/markdownOutput';
padding: 12px;
margin-block: 3px;
border: 2px solid var(--color-border-maxcontrast);
border-radius: var(--border-radius-large);
&:hover {
border-color: var(--color-primary-element);
}
@include markdown-output;
}
}
</style>
7 changes: 6 additions & 1 deletion src/scssmixins/markdownOutput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@
@mixin markdown-output {
overflow-wrap: break-word;

::v-deep {
:deep() {
>:not(:first-child) {
margin-top: 1.5em;
}

a {
color: var(--color-primary-element);
text-decoration: underline;
}

blockquote {
padding-left: 1em;
border-left: 4px solid var(--color-primary-element);
Expand Down
21 changes: 20 additions & 1 deletion src/views/Submit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,15 @@
</template>
</NcEmptyContent>
<NcEmptyContent v-else-if="success || !form.canSubmit"
:title="t('forms', 'Thank you for completing the form!')">
:title="t('forms', 'Thank you for completing the form!')"
:description="form.submissionMessage">
<template #icon>
<IconCheck :size="64" />
</template>
<template v-if="form.submissionMessage" #description>
<!-- eslint-disable-next-line vue/no-v-html -->
<p class="submission-message" v-html="submissionMessageHTML" />
</template>
</NcEmptyContent>
<NcEmptyContent v-else-if="isExpired"
:title="t('forms', 'Form expired')"
Expand Down Expand Up @@ -205,6 +210,16 @@ export default {
return message
},
/**
* Rendered HTML of the custom submission message
*/
submissionMessageHTML() {
if (this.form.submissionMessage && (this.success || !this.form.canSubmit)) {
return this.markdownit.render(this.form.submissionMessage)
}
return ''
},
expirationMessage() {
const relativeDate = moment(this.form.expires, 'X').fromNow()
if (this.isExpired) {
Expand Down Expand Up @@ -359,6 +374,10 @@ export default {
}
}
.submission-message {
@include markdown-output;
}
form {
.question {
// Less padding needed as submit view does not have drag handles
Expand Down
8 changes: 7 additions & 1 deletion tests/Integration/Api/ApiV2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ private function setTestForms() {
'submit_multiple' => false,
'show_expiration' => false,
'last_updated' => 123456789,
'submission_message' => 'Back to website',
'questions' => [
[
'type' => 'short',
Expand Down Expand Up @@ -166,6 +167,7 @@ private function setTestForms() {
'submit_multiple' => false,
'show_expiration' => false,
'last_updated' => 123456789,
'submission_message' => '',
'questions' => [
[
'type' => 'short',
Expand Down Expand Up @@ -214,6 +216,7 @@ public function setUp(): void {
'submit_multiple' => $qb->createNamedParameter($form['submit_multiple'], IQueryBuilder::PARAM_BOOL),
'show_expiration' => $qb->createNamedParameter($form['show_expiration'], IQueryBuilder::PARAM_BOOL),
'last_updated' => $qb->createNamedParameter($form['last_updated'], IQueryBuilder::PARAM_INT),
'submission_message' => $qb->createNamedParameter($form['submission_message'], IQueryBuilder::PARAM_STR),
]);
$qb->execute();
$formId = $qb->getLastInsertId();
Expand Down Expand Up @@ -366,7 +369,8 @@ public function dataGetForms() {
'lastUpdated' => 123456789,
'permissions' => Constants::PERMISSION_ALL,
'partial' => true,
'submissionCount' => 3
'submissionCount' => 3,
'submissionMessage' => 'Back to website'
]]
]
];
Expand Down Expand Up @@ -471,6 +475,7 @@ public function dataGetNewForm() {
'questions' => [],
'shares' => [],
'submissionCount' => 0,
'submissionMessage' => ''
]
]
];
Expand Down Expand Up @@ -523,6 +528,7 @@ public function dataGetFullForm() {
'lastUpdated' => 123456789,
'canSubmit' => true,
'permissions' => Constants::PERMISSION_ALL,
'submissionMessage' => 'Back to website',
'questions' => [
[
'type' => 'short',
Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/Controller/ApiControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,8 @@ public function dataTestCreateNewForm() {
'isAnonymous' => false,
'submitMultiple' => false,
'showExpiration' => false,
'lastUpdated' => 123456789
'lastUpdated' => 123456789,
'submissionMessage' => '',
]]
];
}
Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/FormsMigratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public function setUp(): void {
public function dataExport() {
return [
'exactlyOneOfEach' => [
'expectedJson' => '[{"title":"Link","description":"","created":1646251830,"access":{"permitAllUsers":false,"showToAllUsers":false},"expires":0,"isAnonymous":false,"submitMultiple":false,"showExpiration":false,"lastUpdated":123456789,"questions":[{"id":14,"order":2,"type":"multiple","isRequired":false,"text":"checkbox","description":"huhu","extraSettings":{},"options":[{"text":"ans1"}]}],"submissions":[{"userId":"anyUser@localhost","timestamp":1651354059,"answers":[{"questionId":14,"text":"ans1"}]}]}]'
'expectedJson' => '[{"title":"Link","description":"","created":1646251830,"access":{"permitAllUsers":false,"showToAllUsers":false},"expires":0,"isAnonymous":false,"submitMultiple":false,"showExpiration":false,"lastUpdated":123456789,"submissionMessage":"Back to website","questions":[{"id":14,"order":2,"type":"multiple","isRequired":false,"text":"checkbox","description":"huhu","extraSettings":{},"options":[{"text":"ans1"}]}],"submissions":[{"userId":"anyUser@localhost","timestamp":1651354059,"answers":[{"questionId":14,"text":"ans1"}]}]}]'
]
];
}
Expand Down Expand Up @@ -151,6 +151,7 @@ public function testExport(string $expectedJson) {
$form->setSubmitMultiple(false);
$form->setShowExpiration(false);
$form->setLastUpdated(123456789);
$form->setSubmissionMessage('Back to website');

$this->formsService->expects($this->once())
->method('getQuestions')
Expand Down
4 changes: 3 additions & 1 deletion tests/Unit/Service/FormsServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ public function dataGetForm() {
'displayName' => 'Some User'
]
],
'submissionMessage' => '',
'permissions' => Constants::PERMISSION_ALL
]]
];
Expand Down Expand Up @@ -427,7 +428,8 @@ public function dataGetPublicForm() {
'questions' => [],
'permissions' => [
'submit'
]
],
'submissionMessage' => '',
]]
];
}
Expand Down

0 comments on commit c797fd2

Please sign in to comment.