From 9484551c74059544eb9c14599e9dcbe58b3879cb Mon Sep 17 00:00:00 2001
From: colemanw <coleman@civicrm.org>
Date: Wed, 30 Aug 2023 15:58:35 -0400
Subject: [PATCH] Afform - Add submit_enabled & submit_limit fields

Fixes BasicGetAction handling of default_value - it should be used to set a default value not a default where clause.
---
 Civi/Api4/Generic/BasicGetAction.php          |  5 +-
 .../ang/afGuiEditor/afGuiEditor.component.js  |  2 +
 .../admin/ang/afGuiEditor/config-form.html    | 51 +++++++++++++------
 ext/afform/core/Civi/Api4/Afform.php          | 11 ++++
 .../mock/tests/phpunit/api/v4/AfformTest.php  |  8 +--
 5 files changed, 55 insertions(+), 22 deletions(-)

diff --git a/Civi/Api4/Generic/BasicGetAction.php b/Civi/Api4/Generic/BasicGetAction.php
index 15c9951d8a..1a70866d18 100644
--- a/Civi/Api4/Generic/BasicGetAction.php
+++ b/Civi/Api4/Generic/BasicGetAction.php
@@ -47,7 +47,6 @@ class BasicGetAction extends AbstractGetAction {
    * @param \Civi\Api4\Generic\Result $result
    */
   public function _run(Result $result) {
-    $this->setDefaultWhereClause();
     $this->expandSelectClauseWildcards();
     $values = $this->getRecords();
     $this->formatRawValues($values);
@@ -106,9 +105,9 @@ class BasicGetAction extends AbstractGetAction {
     $fields = $this->entityFields();
     foreach ($records as &$values) {
       foreach ($this->entityFields() as $field) {
-        $values += [$field['name'] => NULL];
+        $values += [$field['name'] => $field['default_value'] ?? NULL];
         if (!empty($field['options'])) {
-          foreach (FormattingUtil::$pseudoConstantSuffixes as $suffix) {
+          foreach ($field['suffixes'] ?? FormattingUtil::$pseudoConstantSuffixes as $suffix) {
             $pseudofield = $field['name'] . ':' . $suffix;
             if (!isset($values[$pseudofield]) && isset($values[$field['name']]) && $this->_isFieldSelected($pseudofield)) {
               $values[$pseudofield] = $values[$field['name']];
diff --git a/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js b/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js
index 571d796006..07eb9fabeb 100644
--- a/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js
+++ b/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js
@@ -98,6 +98,7 @@
         if (editor.mode === 'clone') {
           delete editor.afform.name;
           delete editor.afform.server_route;
+          delete editor.afform.navigation;
           editor.afform.is_dashlet = false;
           editor.afform.title += ' ' + ts('(copy)');
         }
@@ -118,6 +119,7 @@
 
           if (editor.mode === 'create') {
             editor.addEntity(editor.entity);
+            editor.afform.submit_enabled = true;
             editor.afform.create_submission = true;
             editor.layout['#children'].push(afGui.meta.elements.submit.element);
           }
diff --git a/ext/afform/admin/ang/afGuiEditor/config-form.html b/ext/afform/admin/ang/afGuiEditor/config-form.html
index a154730ebb..43f9225e85 100644
--- a/ext/afform/admin/ang/afGuiEditor/config-form.html
+++ b/ext/afform/admin/ang/afGuiEditor/config-form.html
@@ -123,25 +123,46 @@
 
   <!--  Submit actions are only applicable to form types with a submit button (exclude blocks and search forms) -->
   <fieldset ng-if=":: editor.afform.type === 'form'">
-    <legend>{{:: ts('Submit Actions') }}</legend>
+    <legend class="form-inline">
+      {{:: ts('Submissions') }}
+    </legend>
 
-    <div class="form-group" >
-      <label>
-        <input type="checkbox" ng-model="editor.afform.create_submission" >
-        {{:: ts('Log Submissions') }}
+    <p class="form-inline">
+      <label class="radio">
+        <input class="crm-form-radio" type="radio" name="submit_enabled" ng-model="editor.afform.submit_enabled" ng-value="true">
+        {{:: ts('Open') }}
       </label>
-      <p class="help-block">{{:: ts('Keep a log of the date, time, user, and items saved by each form submission.') }}</p>
-    </div>
-
-    <div class="form-group" ng-class="{'has-error': !!config_form.redirect.$error.pattern}">
-      <label for="af_config_redirect">
-        {{:: ts('Post-Submit Page') }}
+      <label class="radio">
+        <input class="crm-form-radio" type="radio" name="submit_enabled" ng-model="editor.afform.submit_enabled" ng-value="false">
+        {{:: ts('Closed') }}
       </label>
-      <div class="input-group">
-        <input ng-model="editor.afform.redirect" name="redirect" class="form-control" id="af_config_redirect" title="{{:: ts('Post-Submit Page') }}" pattern="^((http|https):\/\/|\/|civicrm\/)[-0-9a-zA-Z\/_.]\S+$" title="{{:: ts('Post-Submit Page must be either an absolute url, a relative url or a path starting with CiviCRM') }}" ng-model-options="editor.debounceMode" >
-        <af-gui-token-select class="input-group-addon" model="editor.afform" field="redirect"></af-gui-token-select>
+    </p>
+
+    <div ng-if="editor.afform.submit_enabled">
+
+      <div class="form-group">
+        <label>
+          <input type="checkbox" ng-model="editor.afform.create_submission" >
+          {{:: ts('Log Submissions') }}
+        </label>
+        <p class="help-block">{{:: ts('Keep a log of the date, time, user, and items saved by each form submission.') }}</p>
+      </div>
+
+      <div class="form-inline" ng-if="editor.afform.create_submission">
+        <label for="submit_limit">{{:: ts('Maximum Submissions') }}</label>
+        <input type="number" min="1" step="1" id="submit_limit" ng-model="editor.afform.submit_limit" placeholder="{{:: ts('Unlimited') }}">
+      </div>
+
+      <div class="form-group" ng-class="{'has-error': !!config_form.redirect.$error.pattern}">
+        <label for="af_config_redirect">
+          {{:: ts('Post-Submit Page') }}
+        </label>
+        <div class="input-group">
+          <input ng-model="editor.afform.redirect" name="redirect" class="form-control" id="af_config_redirect" title="{{:: ts('Post-Submit Page') }}" pattern="^((http|https):\/\/|\/|civicrm\/)[-0-9a-zA-Z\/_.]\S+$" title="{{:: ts('Post-Submit Page must be either an absolute url, a relative url or a path starting with CiviCRM') }}" ng-model-options="editor.debounceMode" >
+          <af-gui-token-select class="input-group-addon" model="editor.afform" field="redirect"></af-gui-token-select>
+        </div>
+        <p class="help-block">{{:: ts('Enter a URL or path that the form should redirect to following a successful submission.') }}</p>
       </div>
-      <p class="help-block">{{:: ts('Enter a URL or path that the form should redirect to following a successful submission.') }}</p>
     </div>
   </fieldset>
 </ng-form>
diff --git a/ext/afform/core/Civi/Api4/Afform.php b/ext/afform/core/Civi/Api4/Afform.php
index 58347df675..03e72261ba 100644
--- a/ext/afform/core/Civi/Api4/Afform.php
+++ b/ext/afform/core/Civi/Api4/Afform.php
@@ -218,6 +218,17 @@ class Afform extends Generic\AbstractEntity {
           'name' => 'redirect',
           'title' => E::ts('Post-Submit Page'),
         ],
+        [
+          'name' => 'submit_enabled',
+          'title' => E::ts('Allow Submissions'),
+          'data_type' => 'Boolean',
+          'default_value' => TRUE,
+        ],
+        [
+          'name' => 'submit_limit',
+          'title' => E::ts('Maximum Submissions'),
+          'data_type' => 'Integer',
+        ],
         [
           'name' => 'create_submission',
           'title' => E::ts('Log Submissions'),
diff --git a/ext/afform/mock/tests/phpunit/api/v4/AfformTest.php b/ext/afform/mock/tests/phpunit/api/v4/AfformTest.php
index a673e680a8..6b381ed1fa 100644
--- a/ext/afform/mock/tests/phpunit/api/v4/AfformTest.php
+++ b/ext/afform/mock/tests/phpunit/api/v4/AfformTest.php
@@ -31,10 +31,10 @@ class api_v4_AfformTest extends api_v4_AfformTestCase {
 
   public function getBasicDirectives() {
     return [
-      ['mockPage', ['title' => '', 'description' => '', 'server_route' => 'civicrm/mock-page', 'permission' => ['access Foobar'], 'is_dashlet' => TRUE]],
-      ['mockBareFile', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM'], 'is_dashlet' => FALSE]],
-      ['mockFoo', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM']]],
-      ['mock-weird-name', ['title' => 'Weird Name', 'description' => '', 'permission' => ['access CiviCRM']]],
+      ['mockPage', ['title' => '', 'description' => '', 'server_route' => 'civicrm/mock-page', 'permission' => ['access Foobar'], 'is_dashlet' => TRUE, 'submit_enabled' => TRUE]],
+      ['mockBareFile', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM'], 'is_dashlet' => FALSE, 'submit_enabled' => TRUE]],
+      ['mockFoo', ['title' => '', 'description' => '', 'permission' => ['access CiviCRM']], 'submit_enabled' => TRUE],
+      ['mock-weird-name', ['title' => 'Weird Name', 'description' => '', 'permission' => ['access CiviCRM']], 'submit_enabled' => TRUE],
     ];
   }
 
-- 
2.25.1