dev/core#2141 - "Add Mail Account" - Allow hookable listing of setup links
authorTim Otten <totten@civicrm.org>
Fri, 30 Oct 2020 06:59:51 +0000 (23:59 -0700)
committerTim Otten <totten@civicrm.org>
Fri, 30 Oct 2020 10:40:16 +0000 (03:40 -0700)
Overview
--------

For certain types of mail accounts -- such as Google Mail and Microsoft
Exchange Online -- the setup process may require interaction with a remote
web-service.  The web-service provides some critical details (like
authentication tokens) and some handy details (like their username / email
address).

If the supports one of these services, then this revision will enable a
setup process.  It alters the "Add Mail Account" action to use a more
fine-tuned procedure.

Before
------

* Navigate to "Administer => CiviMail => Mail Accounts".
* Below the table, there is a singular button "Add Mail Account".
* Click the button.
* It opens an empty form for configuring the account.

After
-----

By default, the UX is the same.  However, if you have an extension like
`oauth-client`, then it changes:

* Navigate to "Administer => CiviMail => Mail Accounts".
* Below the table, there is a select box for "Add Mail Account". It lists different account types.
* Choose one of the options from the dropbox. The step depends on...
    * If you choose "Standard Mail Account", it opens the empty config form.
    * If you choose "Microsoft Exchange Online", it redirects to MS to get authorization
      from the user. Then, it redirects and prefills the config form.

CRM/Admin/Page/MailSettings.php
CRM/Core/BAO/MailSettings.php
CRM/Mailing/Page/AJAX.php
CRM/Mailing/xml/Menu/Mailing.xml
CRM/Utils/Hook.php
templates/CRM/Admin/Page/MailSettings.tpl

index 6ede83649efaeff2a72b1afbf1314281e3902a70..c3dca8c85342c505c791ecfcda0eff51039243dc 100644 (file)
@@ -107,6 +107,11 @@ class CRM_Admin_Page_MailSettings extends CRM_Core_Page_Basic {
     }
 
     $this->assign('rows', $allMailSettings);
+
+    $setupActions = CRM_Core_BAO_MailSettings::getSetupActions();
+    if (count($setupActions) > 1 || !isset($setupActions['standard'])) {
+      $this->assign('setupActions', $setupActions);
+    }
   }
 
   /**
index e7ea7b196b93d97afa7386f3d5781450c092445d..26086ea2e8e4cac27f890c484a358c8e475da1c0 100644 (file)
@@ -23,6 +23,30 @@ class CRM_Core_BAO_MailSettings extends CRM_Core_DAO_MailSettings {
     parent::__construct();
   }
 
+  /**
+   * Get a list of setup-actions.
+   *
+   * @return array
+   *   List of available actions. See description in the hook-docs.
+   * @see CRM_Utils_Hook::mailSetupActions()
+   */
+  public static function getSetupActions() {
+    $setupActions = [];
+    $setupActions['standard'] = [
+      'title' => ts('Standard Mail Account'),
+      'callback' => ['CRM_Core_BAO_MailSettings', 'setupStandardAccount'],
+    ];
+
+    CRM_Utils_Hook::mailSetupActions($setupActions);
+    return $setupActions;
+  }
+
+  public static function setupStandardAccount($setupAction) {
+    return [
+      'url' => CRM_Utils_System::url('civicrm/admin/mailSettings', 'action=add&reset=1', TRUE, NULL, FALSE),
+    ];
+  }
+
   /**
    * Return the DAO object containing to the default row of
    * civicrm_mail_settings and cache it for further calls
index e5b4fb9e8fdcd232cdf509e1fb3f6dc6ea640a98..5af3033f931f8c1aefcf20800d3c85d408887339 100644 (file)
  */
 class CRM_Mailing_Page_AJAX {
 
+  /**
+   * Kick off the "Add Mail Account" process for some given type of account.
+   *
+   * Ex: 'civicrm/ajax/setupMailAccount?type=standard'
+   * Ex: 'civicrm/ajax/setupMailAccount?type=oauth_1'
+   *
+   * @see CRM_Core_BAO_MailSettings::getSetupActions()
+   * @throws \CRM_Core_Exception
+   */
+  public static function setup() {
+    $type = CRM_Utils_Request::retrieve('type', 'String');
+    $setupActions = CRM_Core_BAO_MailSettings::getSetupActions();
+    $setupAction = $setupActions[$type] ?? NULL;
+    if ($setupAction === NULL) {
+      throw new \CRM_Core_Exception("Cannot setup mail account. Invalid type requested.");
+    }
+
+    $result = call_user_func($setupAction['callback'], $setupAction);
+    if (isset($result['url'])) {
+      CRM_Utils_System::redirect($result['url']);
+    }
+    else {
+      throw new \CRM_Core_Exception("Cannot setup mail account. Setup does not have a URL.");
+    }
+  }
+
   /**
    * Fetch the template text/html messages
    */
index 78ac7ebe0654962a97646554a690d577b0e21a21..3c4446704fb317d7eda7d11b609c0dfaf7cc2777 100644 (file)
     <page_callback>CRM_Mailing_Page_AJAX::getContactMailings</page_callback>
     <access_arguments>access CiviCRM</access_arguments>
   </item>
+  <item>
+    <path>civicrm/ajax/setupMailAccount</path>
+    <page_callback>CRM_Mailing_Page_AJAX::setup</page_callback>
+    <access_arguments>access CiviCRM,access CiviMail</access_arguments>
+  </item>
   <item>
     <path>civicrm/mailing/url</path>
     <page_callback>CRM_Mailing_Page_Url</page_callback>
index a987971774b41dc02e2bf2a00254168dff9d95a5..4eb7f470bcd16949a0e9f7e4410f93aa6473c34a 100644 (file)
@@ -1042,6 +1042,24 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * When adding a new "Mail Account" (`MailSettings`), present a menu of setup
+   * options.
+   *
+   * @param array $setupActions
+   *   Each item has a symbolic-key, and it has the properties:
+   *     - title: string
+   *     - callback: string|array, the function which starts the setup process.
+   *        The function is expected to return a 'url' for the config screen.
+   * @return mixed
+   */
+  public static function mailSetupActions(&$setupActions) {
+    return self::singleton()->invoke(['setupActions'], $setupActions, self::$_nullObject, self::$_nullObject,
+      self::$_nullObject, self::$_nullObject, self::$_nullObject,
+      'civicrm_mailSetupActions'
+    );
+  }
+
   /**
    * This hook is called when composing a mailing. You can include / exclude other groups as needed.
    *
index f7e2bde5c4b9c875d0741af52b06d9bf6e4c9d30..18f1d67148d371cec73ab297df18e794bbea7088 100644 (file)
       {ts}None found.{/ts}
     </div>
 {/if}
-  <div class="action-link">
-    {crmButton q="action=add&reset=1" id="newMailSettings"  icon="plus-circle"}{ts}Add Mail Account{/ts}{/crmButton}
-    {crmButton p="civicrm/admin" q="reset=1" class="cancel" icon="times"}{ts}Done{/ts}{/crmButton}
-  </div>
+    {if $setupActions}
+        <form>
+            <select id="crm-mail-setup" name="crm-mail-setup" class="crm-select2 crm-form-select" aria-label="{ts}Add Mail Account{/ts}">
+                <option value="" aria-hidden="true">{ts}Add Mail Account{/ts}</option>
+                {foreach from=$setupActions key=setupActionsName item=setupAction}
+                    <option value="{$setupActionsName|escape}">{$setupAction.title|escape}</option>
+                {/foreach}
+            </select>
+        </form>
+    {else}
+        <div class="action-link">
+            {crmButton q="action=add&reset=1" id="newMailSettings"  icon="plus-circle"}{ts}Add Mail Account{/ts}{/crmButton}
+            {crmButton p="civicrm/admin" q="reset=1" class="cancel" icon="times"}{ts}Done{/ts}{/crmButton}
+        </div>
+    {/if}
+
 {/if}
 </div>
+{literal}
+    <script type="text/javascript">
+        cj('#crm-mail-setup').val('');
+        cj('#crm-mail-setup').on('select2-selecting', function(event) {
+            if (!event.val) {
+                return;
+            }
+            event.stopPropagation();
+            var url = CRM.url('civicrm/ajax/setupMailAccount', {type: event.val});
+            window.location = url;
+        });
+    </script>
+{/literal}