xref: /template/strap/action/login.php (revision 858cf17eaf876d049c21c4b2fd66da5ea3852ff2)
1a6bf47aaSNickeau<?php
2a6bf47aaSNickeau/**
3a6bf47aaSNickeau * Action Component
4a6bf47aaSNickeau * Add a button in the edit toolbar
5a6bf47aaSNickeau *
6a6bf47aaSNickeau * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7a6bf47aaSNickeau * @author     Nicolas GERARD
8a6bf47aaSNickeau */
9a6bf47aaSNickeau
10a6bf47aaSNickeauuse ComboStrap\Identity;
1104fd306cSNickeauuse ComboStrap\IdentityFormsHelper;
12a6bf47aaSNickeauuse ComboStrap\LogUtility;
13a6bf47aaSNickeauuse ComboStrap\PluginUtility;
1404fd306cSNickeauuse ComboStrap\Site;
1504fd306cSNickeauuse ComboStrap\SiteConfig;
160581ab2eSgerardnicouse dokuwiki\Form\Form;
170581ab2eSgerardnicouse dokuwiki\Form\InputElement;
18a6bf47aaSNickeauuse dokuwiki\Menu\Item\Login;
19a6bf47aaSNickeau
20a6bf47aaSNickeauif (!defined('DOKU_INC')) die();
2137748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
22a6bf47aaSNickeau
23a6bf47aaSNickeau/**
24a6bf47aaSNickeau * Class action_plugin_combo_login
25a6bf47aaSNickeau *
26a6bf47aaSNickeau * $conf['rememberme']
27a6bf47aaSNickeau */
28a6bf47aaSNickeauclass action_plugin_combo_login extends DokuWiki_Action_Plugin
29a6bf47aaSNickeau{
30a6bf47aaSNickeau
31a6bf47aaSNickeau
32a6bf47aaSNickeau    const CANONICAL = Identity::CANONICAL;
33a6bf47aaSNickeau    const TAG = "login";
34a6bf47aaSNickeau    const FORM_LOGIN_CLASS = "form-" . self::TAG;
35a6bf47aaSNickeau
36a6bf47aaSNickeau    const CONF_ENABLE_LOGIN_FORM = "enableLoginForm";
3704fd306cSNickeau    const FIELD_SET_TO_DELETE = ["fieldsetopen", "fieldsetclose"];
38a6bf47aaSNickeau
39a6bf47aaSNickeau
400581ab2eSgerardnico    /**
410581ab2eSgerardnico     * Update the old form
420581ab2eSgerardnico     * @param Doku_Form $form
430581ab2eSgerardnico     * @return void
440581ab2eSgerardnico     */
450581ab2eSgerardnico    private static function updateDokuFormLogin(Doku_Form &$form)
46a6bf47aaSNickeau    {
47a6bf47aaSNickeau        /**
480581ab2eSgerardnico         * The Login page is an admin page created via buffer
49a6bf47aaSNickeau         * We print before the forms
50a6bf47aaSNickeau         * to avoid a FOUC
51a6bf47aaSNickeau         */
5204fd306cSNickeau        print IdentityFormsHelper::getHtmlStyleTag(self::TAG);
53a6bf47aaSNickeau
54a6bf47aaSNickeau
554cadd4f8SNickeau        $form->params["class"] = Identity::FORM_IDENTITY_CLASS . " " . self::FORM_LOGIN_CLASS;
56a6bf47aaSNickeau
57a6bf47aaSNickeau
58a6bf47aaSNickeau        /**
59a6bf47aaSNickeau         * Heading
60a6bf47aaSNickeau         */
6104fd306cSNickeau        $newFormContent[] = IdentityFormsHelper::getHeaderHTML($form, self::FORM_LOGIN_CLASS);
62a6bf47aaSNickeau
63a6bf47aaSNickeau        /**
64a6bf47aaSNickeau         * Field
65a6bf47aaSNickeau         */
66a6bf47aaSNickeau        foreach ($form->_content as $field) {
67a6bf47aaSNickeau            if (!is_array($field)) {
68a6bf47aaSNickeau                continue;
69a6bf47aaSNickeau            }
70a6bf47aaSNickeau            $fieldName = $field["name"];
71a6bf47aaSNickeau            if ($fieldName == null) {
72a6bf47aaSNickeau                // this is not an input field
73a6bf47aaSNickeau                if ($field["type"] == "submit") {
74a6bf47aaSNickeau                    /**
75a6bf47aaSNickeau                     * This is important to keep the submit element intact
76a6bf47aaSNickeau                     * for forms integration such as captcha
77a6bf47aaSNickeau                     * They search the submit button to insert before it
78a6bf47aaSNickeau                     */
79a6bf47aaSNickeau                    $classes = "btn btn-primary btn-block";
80a6bf47aaSNickeau                    if (isset($field["class"])) {
81a6bf47aaSNickeau                        $field["class"] = $field["class"] . " " . $classes;
82a6bf47aaSNickeau                    } else {
83a6bf47aaSNickeau                        $field["class"] = $classes;
84a6bf47aaSNickeau                    }
85a6bf47aaSNickeau                    $newFormContent[] = $field;
86a6bf47aaSNickeau                }
87a6bf47aaSNickeau                continue;
88a6bf47aaSNickeau            }
89a6bf47aaSNickeau            switch ($fieldName) {
90a6bf47aaSNickeau                case "u":
91a6bf47aaSNickeau                    $loginText = $field["_text"];
92a6bf47aaSNickeau                    $loginValue = $field["value"];
93a6bf47aaSNickeau                    $loginHTMLField = <<<EOF
94a6bf47aaSNickeau<div class="form-floating">
95*858cf17eSNico    <input type="text" id="inputUserName" class="form-control" placeholder="$loginText" autocomplete="username" aria-label="Username" required="required" autofocus="" name="u" value="$loginValue">
96a6bf47aaSNickeau    <label for="inputUserName">$loginText</label>
97a6bf47aaSNickeau</div>
98a6bf47aaSNickeauEOF;
99a6bf47aaSNickeau                    $newFormContent[] = $loginHTMLField;
100a6bf47aaSNickeau                    break;
101a6bf47aaSNickeau                case "p":
102a6bf47aaSNickeau                    $passwordText = $field["_text"];
103a6bf47aaSNickeau                    $passwordFieldHTML = <<<EOF
104a6bf47aaSNickeau<div class="form-floating">
105*858cf17eSNico    <input type="password" id="inputPassword" class="form-control" aria-label="Password" placeholder="$passwordText" required="required" name="p">
106a6bf47aaSNickeau    <label for="inputPassword">$passwordText</label>
107a6bf47aaSNickeau</div>
108a6bf47aaSNickeauEOF;
109a6bf47aaSNickeau                    $newFormContent[] = $passwordFieldHTML;
110a6bf47aaSNickeau                    break;
111a6bf47aaSNickeau                case "r":
112a6bf47aaSNickeau                    $rememberText = $field["_text"];
113a6bf47aaSNickeau                    $rememberValue = $field["value"];
114a6bf47aaSNickeau                    $rememberMeHtml = <<<EOF
115a6bf47aaSNickeau<div class="checkbox rememberMe">
116a6bf47aaSNickeau    <label><input type="checkbox" id="remember__me" name="r" value="$rememberValue"> $rememberText</label>
117a6bf47aaSNickeau</div>
118a6bf47aaSNickeauEOF;
119a6bf47aaSNickeau                    $newFormContent[] = $rememberMeHtml;
120a6bf47aaSNickeau                    break;
121a6bf47aaSNickeau                default:
122a6bf47aaSNickeau                    $tag = self::TAG;
123a6bf47aaSNickeau                    LogUtility::msg("The $tag field name ($fieldName) is unknown", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
124a6bf47aaSNickeau
125a6bf47aaSNickeau
126a6bf47aaSNickeau            }
127a6bf47aaSNickeau        }
128a6bf47aaSNickeau
129a6bf47aaSNickeau
130a6bf47aaSNickeau        $registerHtml = action_plugin_combo_registration::getRegisterLinkAndParagraph();
131a6bf47aaSNickeau        if (!empty($registerHtml)) {
132a6bf47aaSNickeau            $newFormContent[] = $registerHtml;
133a6bf47aaSNickeau        }
134a6bf47aaSNickeau        $resendPwdHtml = action_plugin_combo_resend::getResendPasswordParagraphWithLinkToFormPage();
135a6bf47aaSNickeau        if (!empty($resendPwdHtml)) {
136a6bf47aaSNickeau            $newFormContent[] = $resendPwdHtml;
137a6bf47aaSNickeau        }
138a6bf47aaSNickeau
139a6bf47aaSNickeau        /**
140a6bf47aaSNickeau         * Set the new in place of the old one
141a6bf47aaSNickeau         */
142a6bf47aaSNickeau        $form->_content = $newFormContent;
143a6bf47aaSNickeau    }
144a6bf47aaSNickeau
1450581ab2eSgerardnico
1460581ab2eSgerardnico    function register(Doku_Event_Handler $controller)
147c3437056SNickeau    {
1480581ab2eSgerardnico        /**
1490581ab2eSgerardnico         * To modify the form and add class
1500581ab2eSgerardnico         *
1510581ab2eSgerardnico         * The event HTML_LOGINFORM_OUTPUT is deprecated
1520581ab2eSgerardnico         * for FORM_LOGIN_OUTPUT
1530581ab2eSgerardnico         *
1540581ab2eSgerardnico         * The difference is on the type of object that we got in the event
1550581ab2eSgerardnico         */
15604fd306cSNickeau        if (SiteConfig::getConfValue(self::CONF_ENABLE_LOGIN_FORM, 1)) {
1570581ab2eSgerardnico
1580581ab2eSgerardnico            /**
1590581ab2eSgerardnico             * Old event: Deprecated object passed by the event but still in use
1600581ab2eSgerardnico             * https://www.dokuwiki.org/devel:event:html_loginform_output
1610581ab2eSgerardnico             */
1620581ab2eSgerardnico            $controller->register_hook('HTML_LOGINFORM_OUTPUT', 'BEFORE', $this, 'handle_login_html', array());
1630581ab2eSgerardnico
1640581ab2eSgerardnico            /**
1650581ab2eSgerardnico             * New Event: using the new object but only in use in
1660581ab2eSgerardnico             * the {@link https://codesearch.dokuwiki.org/xref/dokuwiki/lib/plugins/authad/action.php authad plugin}
1670581ab2eSgerardnico             * (ie login against active directory)
1680581ab2eSgerardnico             *
1690581ab2eSgerardnico             * https://www.dokuwiki.org/devel:event:form_login_output
1700581ab2eSgerardnico             */
1710581ab2eSgerardnico            $controller->register_hook('FORM_LOGIN_OUTPUT', 'BEFORE', $this, 'handle_login_html', array());
172c3437056SNickeau        }
173a6bf47aaSNickeau
1740581ab2eSgerardnico
1750581ab2eSgerardnico    }
1760581ab2eSgerardnico
1770581ab2eSgerardnico    function handle_login_html(&$event, $param): void
1780581ab2eSgerardnico    {
1790581ab2eSgerardnico
1800581ab2eSgerardnico        $form = &$event->data;
1810581ab2eSgerardnico        $class = get_class($form);
1820581ab2eSgerardnico        switch ($class) {
1830581ab2eSgerardnico            case Doku_Form::class:
1840581ab2eSgerardnico                /**
1850581ab2eSgerardnico                 * Old one
1860581ab2eSgerardnico                 * @var Doku_Form $form
1870581ab2eSgerardnico                 */
1880581ab2eSgerardnico                self::updateDokuFormLogin($form);
1890581ab2eSgerardnico                return;
1900581ab2eSgerardnico            case dokuwiki\Form\Form::class;
1910581ab2eSgerardnico                /**
1920581ab2eSgerardnico                 * New One
1930581ab2eSgerardnico                 * @var Form $form
1940581ab2eSgerardnico                 */
1950581ab2eSgerardnico                self::updateNewFormLogin($form);
1960581ab2eSgerardnico                return;
1970581ab2eSgerardnico        }
1980581ab2eSgerardnico
1990581ab2eSgerardnico
2000581ab2eSgerardnico    }
2010581ab2eSgerardnico
2020581ab2eSgerardnico
203a6bf47aaSNickeau    /**
204a6bf47aaSNickeau     * Login
205a6bf47aaSNickeau     * @return string
206a6bf47aaSNickeau     */
2070581ab2eSgerardnico    public static function getLoginParagraphWithLinkToFormPage(): string
208a6bf47aaSNickeau    {
209a6bf47aaSNickeau
210a6bf47aaSNickeau        $loginPwLink = (new Login())->asHtmlLink('', false);
211a6bf47aaSNickeau        global $lang;
212a6bf47aaSNickeau        $loginText = $lang['btn_login'];
213a6bf47aaSNickeau        return <<<EOF
214a6bf47aaSNickeau<p class="login">$loginText ? : $loginPwLink</p>
215a6bf47aaSNickeauEOF;
216a6bf47aaSNickeau
217a6bf47aaSNickeau    }
2180581ab2eSgerardnico
2190581ab2eSgerardnico    /**
2200581ab2eSgerardnico     * https://www.dokuwiki.org/devel:form - documentation
2210581ab2eSgerardnico     * @param Form $form
2220581ab2eSgerardnico     * @return void
2230581ab2eSgerardnico     */
2240581ab2eSgerardnico    private static function updateNewFormLogin(Form &$form)
2250581ab2eSgerardnico    {
2260581ab2eSgerardnico        /**
2270581ab2eSgerardnico         * The Login page is an admin page created via buffer
2280581ab2eSgerardnico         * We print before the forms
2290581ab2eSgerardnico         * to avoid a FOUC
2300581ab2eSgerardnico         */
23104fd306cSNickeau        print IdentityFormsHelper::getHtmlStyleTag(self::TAG);
2320581ab2eSgerardnico
2330581ab2eSgerardnico
2340581ab2eSgerardnico        $form->addClass(Identity::FORM_IDENTITY_CLASS . " " . self::FORM_LOGIN_CLASS);
2350581ab2eSgerardnico
23604fd306cSNickeau
2370581ab2eSgerardnico        /**
2380581ab2eSgerardnico         * Heading
2390581ab2eSgerardnico         */
24004fd306cSNickeau        $headerHTML = IdentityFormsHelper::getHeaderHTML($form, self::FORM_LOGIN_CLASS);
2410581ab2eSgerardnico        if ($headerHTML != "") {
2420581ab2eSgerardnico            $form->addHTML($headerHTML, 1);
243a6bf47aaSNickeau        }
244a6bf47aaSNickeau
2450581ab2eSgerardnico
2460581ab2eSgerardnico        /**
24704fd306cSNickeau         * Fieldset and br delete
2480581ab2eSgerardnico         */
24904fd306cSNickeau        IdentityFormsHelper::deleteFieldSetAndBrFromForm($form);
2500581ab2eSgerardnico
2510581ab2eSgerardnico        /**
2520581ab2eSgerardnico         * Field
2530581ab2eSgerardnico         */
25404fd306cSNickeau        IdentityFormsHelper::toBootStrapSubmitButton($form);
2550581ab2eSgerardnico
25604fd306cSNickeau        /**
25704fd306cSNickeau         * Name
25804fd306cSNickeau         */
2590581ab2eSgerardnico        $userPosition = $form->findPositionByAttribute("name", "u");
26004fd306cSNickeau        if ($userPosition === false) {
2610581ab2eSgerardnico            LogUtility::msg("Internal error: No user field found");
2620581ab2eSgerardnico            return;
2630581ab2eSgerardnico        }
2640581ab2eSgerardnico        /**
2650581ab2eSgerardnico         * @var InputElement $userField
2660581ab2eSgerardnico         */
2670581ab2eSgerardnico        $userField = $form->getElementAt($userPosition);
2680581ab2eSgerardnico        $newUserField = new InputElement($userField->getType(), "u");
2690581ab2eSgerardnico        $loginText = $userField->getLabel()->val();
2700581ab2eSgerardnico        foreach ($userField->attrs() as $keyAttr => $valueAttr) {
2710581ab2eSgerardnico            $newUserField->attr($keyAttr, $valueAttr);
2720581ab2eSgerardnico        }
2730581ab2eSgerardnico        $newUserField->addClass("form-control");
2740581ab2eSgerardnico        $newUserField->attr("placeholder", $loginText);
2750581ab2eSgerardnico        $newUserField->attr("required", "required");
2760581ab2eSgerardnico        $newUserField->attr("autofocus", "");
277*858cf17eSNico        $newUserField->attr("autocomplete", "username");
278*858cf17eSNico        $newUserField->attr("aria-label", "username");
2790581ab2eSgerardnico        $userFieldId = $userField->attr("id");
2800581ab2eSgerardnico
2810581ab2eSgerardnico        $form->replaceElement($newUserField, $userPosition);
2820581ab2eSgerardnico
2830581ab2eSgerardnico        $form->addHTML("<div class=\"form-floating\">", $userPosition);
2840581ab2eSgerardnico        $form->addHTML("<label for=\"$userFieldId\">$loginText</label>", $userPosition + 2);
2850581ab2eSgerardnico        $form->addHTML("</div>", $userPosition + 3);
2860581ab2eSgerardnico
2870581ab2eSgerardnico
2880581ab2eSgerardnico        $pwdPosition = $form->findPositionByAttribute("name", "p");
28904fd306cSNickeau        if ($pwdPosition === false) {
2900581ab2eSgerardnico            LogUtility::msg("Internal error: No password field found");
2910581ab2eSgerardnico            return;
2920581ab2eSgerardnico        }
2930581ab2eSgerardnico        $pwdField = $form->getElementAt($pwdPosition);
2940581ab2eSgerardnico        $newPwdField = new InputElement($pwdField->getType(), "p");
2950581ab2eSgerardnico        foreach ($pwdField->attrs() as $keyAttr => $valueAttr) {
2960581ab2eSgerardnico            $newPwdField->attr($keyAttr, $valueAttr);
2970581ab2eSgerardnico        }
2980581ab2eSgerardnico        $newPwdField->addClass("form-control");
2990581ab2eSgerardnico        $passwordText = $pwdField->getLabel()->val();
3000581ab2eSgerardnico        $newPwdField->attr("placeholder", $passwordText);
3010581ab2eSgerardnico        $newPwdField->attr("required", "required");
302*858cf17eSNico        $newPwdField->attr("aria-label", "password");
3030581ab2eSgerardnico        $pwdFieldId = $newPwdField->attr("id");
3040581ab2eSgerardnico        if (empty($pwdFieldId)) {
3050581ab2eSgerardnico            $pwdFieldId = "input__password";
3060581ab2eSgerardnico            $newPwdField->id($pwdFieldId);
3070581ab2eSgerardnico        }
3080581ab2eSgerardnico        $form->replaceElement($newPwdField, $pwdPosition);
3090581ab2eSgerardnico
3100581ab2eSgerardnico
3110581ab2eSgerardnico        $form->addHTML("<div class=\"form-floating\">", $pwdPosition);
3120581ab2eSgerardnico        $form->addHTML("<label for=\"$pwdFieldId\">$passwordText</label>", $pwdPosition + 2);
3130581ab2eSgerardnico        $form->addHTML("</div>", $pwdPosition + 3);
3140581ab2eSgerardnico
3150581ab2eSgerardnico
3160581ab2eSgerardnico        $rememberPosition = $form->findPositionByAttribute("name", "r");
31704fd306cSNickeau        if ($rememberPosition === false) {
3180581ab2eSgerardnico            LogUtility::msg("Internal error: No remember field found");
3190581ab2eSgerardnico            return;
3200581ab2eSgerardnico        }
3210581ab2eSgerardnico        $rememberField = $form->getElementAt($rememberPosition);
3220581ab2eSgerardnico        $newRememberField = new InputElement($rememberField->getType(), "r");
3230581ab2eSgerardnico        foreach ($rememberField->attrs() as $keyAttr => $valueAttr) {
3240581ab2eSgerardnico            $newRememberField->attr($keyAttr, $valueAttr);
3250581ab2eSgerardnico        }
3260581ab2eSgerardnico        $newRememberField->addClass("form-check-input");
3270581ab2eSgerardnico        $form->replaceElement($newRememberField, $rememberPosition);
3280581ab2eSgerardnico
3290581ab2eSgerardnico        $remberText = $rememberField->getLabel()->val();
3300581ab2eSgerardnico        $remFieldId = $newRememberField->attr("id");
3310581ab2eSgerardnico
3320581ab2eSgerardnico        $form->addHTML("<div class=\"form-check py-2\">", $rememberPosition);
3330581ab2eSgerardnico        $form->addHTML("<label for=\"$remFieldId\" class=\"form-check-label\">$remberText</label>", $rememberPosition + 2);
3340581ab2eSgerardnico        $form->addHTML("</div>", $rememberPosition + 3);
3350581ab2eSgerardnico
3360581ab2eSgerardnico
3370581ab2eSgerardnico//        $registerHtml = action_plugin_combo_registration::getRegisterLinkAndParagraph();
3380581ab2eSgerardnico//        if (!empty($registerHtml)) {
3390581ab2eSgerardnico//            $newFormContent[] = $registerHtml;
3400581ab2eSgerardnico//        }
3410581ab2eSgerardnico//
3420581ab2eSgerardnico//        $resendPwdHtml = action_plugin_combo_resend::getResendPasswordParagraphWithLinkToFormPage();
3430581ab2eSgerardnico//        if (!empty($resendPwdHtml)) {
3440581ab2eSgerardnico//            $newFormContent[] = $resendPwdHtml;
3450581ab2eSgerardnico//        }
3460581ab2eSgerardnico
3470581ab2eSgerardnico    }
3480581ab2eSgerardnico
3490581ab2eSgerardnico}
35004fd306cSNickeau
351