xref: /plugin/combo/action/login.php (revision 0581ab2e899a1c46658568052899346bcaa91bb5)
1<?php
2/**
3 * Action Component
4 * Add a button in the edit toolbar
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Nicolas GERARD
8 */
9
10use ComboStrap\Identity;
11use ComboStrap\LogUtility;
12use ComboStrap\PluginUtility;
13use dokuwiki\Form\Form;
14use dokuwiki\Form\InputElement;
15use dokuwiki\Menu\Item\Login;
16
17if (!defined('DOKU_INC')) die();
18require_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
19
20/**
21 * Class action_plugin_combo_login
22 *
23 * $conf['rememberme']
24 */
25class action_plugin_combo_login extends DokuWiki_Action_Plugin
26{
27
28
29    const CANONICAL = Identity::CANONICAL;
30    const TAG = "login";
31    const FORM_LOGIN_CLASS = "form-" . self::TAG;
32
33    const CONF_ENABLE_LOGIN_FORM = "enableLoginForm";
34
35
36    /**
37     * Update the old form
38     * @param Doku_Form $form
39     * @return void
40     */
41    private static function updateDokuFormLogin(Doku_Form &$form)
42    {
43        /**
44         * The Login page is an admin page created via buffer
45         * We print before the forms
46         * to avoid a FOUC
47         */
48        print Identity::getHtmlStyleTag(self::TAG);
49
50
51        $form->params["class"] = Identity::FORM_IDENTITY_CLASS . " " . self::FORM_LOGIN_CLASS;
52
53
54        /**
55         * Heading
56         */
57        $newFormContent[] = Identity::getHeaderHTML($form, self::FORM_LOGIN_CLASS);
58
59        /**
60         * Field
61         */
62        foreach ($form->_content as $field) {
63            if (!is_array($field)) {
64                continue;
65            }
66            $fieldName = $field["name"];
67            if ($fieldName == null) {
68                // this is not an input field
69                if ($field["type"] == "submit") {
70                    /**
71                     * This is important to keep the submit element intact
72                     * for forms integration such as captcha
73                     * They search the submit button to insert before it
74                     */
75                    $classes = "btn btn-primary btn-block";
76                    if (isset($field["class"])) {
77                        $field["class"] = $field["class"] . " " . $classes;
78                    } else {
79                        $field["class"] = $classes;
80                    }
81                    $newFormContent[] = $field;
82                }
83                continue;
84            }
85            switch ($fieldName) {
86                case "u":
87                    $loginText = $field["_text"];
88                    $loginValue = $field["value"];
89                    $loginHTMLField = <<<EOF
90<div class="form-floating">
91    <input type="text" id="inputUserName" class="form-control" placeholder="$loginText" required="required" autofocus="" name="u" value="$loginValue">
92    <label for="inputUserName">$loginText</label>
93</div>
94EOF;
95                    $newFormContent[] = $loginHTMLField;
96                    break;
97                case "p":
98                    $passwordText = $field["_text"];
99                    $passwordFieldHTML = <<<EOF
100<div class="form-floating">
101    <input type="password" id="inputPassword" class="form-control" placeholder="$passwordText" required="required" name="p">
102    <label for="inputPassword">$passwordText</label>
103</div>
104EOF;
105                    $newFormContent[] = $passwordFieldHTML;
106                    break;
107                case "r":
108                    $rememberText = $field["_text"];
109                    $rememberValue = $field["value"];
110                    $rememberMeHtml = <<<EOF
111<div class="checkbox rememberMe">
112    <label><input type="checkbox" id="remember__me" name="r" value="$rememberValue"> $rememberText</label>
113</div>
114EOF;
115                    $newFormContent[] = $rememberMeHtml;
116                    break;
117                default:
118                    $tag = self::TAG;
119                    LogUtility::msg("The $tag field name ($fieldName) is unknown", LogUtility::LVL_MSG_ERROR, self::CANONICAL);
120
121
122            }
123        }
124
125
126        $registerHtml = action_plugin_combo_registration::getRegisterLinkAndParagraph();
127        if (!empty($registerHtml)) {
128            $newFormContent[] = $registerHtml;
129        }
130        $resendPwdHtml = action_plugin_combo_resend::getResendPasswordParagraphWithLinkToFormPage();
131        if (!empty($resendPwdHtml)) {
132            $newFormContent[] = $resendPwdHtml;
133        }
134
135        /**
136         * Set the new in place of the old one
137         */
138        $form->_content = $newFormContent;
139    }
140
141
142    function register(Doku_Event_Handler $controller)
143    {
144        /**
145         * To modify the form and add class
146         *
147         * The event HTML_LOGINFORM_OUTPUT is deprecated
148         * for FORM_LOGIN_OUTPUT
149         *
150         * The difference is on the type of object that we got in the event
151         */
152        if (PluginUtility::getConfValue(self::CONF_ENABLE_LOGIN_FORM, 1)) {
153
154            /**
155             * Old event: Deprecated object passed by the event but still in use
156             * https://www.dokuwiki.org/devel:event:html_loginform_output
157             */
158            $controller->register_hook('HTML_LOGINFORM_OUTPUT', 'BEFORE', $this, 'handle_login_html', array());
159
160            /**
161             * New Event: using the new object but only in use in
162             * the {@link https://codesearch.dokuwiki.org/xref/dokuwiki/lib/plugins/authad/action.php authad plugin}
163             * (ie login against active directory)
164             *
165             * https://www.dokuwiki.org/devel:event:form_login_output
166             */
167            $controller->register_hook('FORM_LOGIN_OUTPUT', 'BEFORE', $this, 'handle_login_html', array());
168        }
169
170
171    }
172
173    function handle_login_html(&$event, $param): void
174    {
175
176        $form = &$event->data;
177        $class = get_class($form);
178        switch ($class) {
179            case Doku_Form::class:
180                /**
181                 * Old one
182                 * @var Doku_Form $form
183                 */
184                self::updateDokuFormLogin($form);
185                return;
186            case dokuwiki\Form\Form::class;
187                /**
188                 * New One
189                 * @var Form $form
190                 */
191                self::updateNewFormLogin($form);
192                return;
193        }
194
195
196    }
197
198
199    /**
200     * Login
201     * @return string
202     */
203    public static function getLoginParagraphWithLinkToFormPage(): string
204    {
205
206        $loginPwLink = (new Login())->asHtmlLink('', false);
207        global $lang;
208        $loginText = $lang['btn_login'];
209        return <<<EOF
210<p class="login">$loginText ? : $loginPwLink</p>
211EOF;
212
213    }
214
215    /**
216     * https://www.dokuwiki.org/devel:form - documentation
217     * @param Form $form
218     * @return void
219     */
220    private static function updateNewFormLogin(Form &$form)
221    {
222        /**
223         * The Login page is an admin page created via buffer
224         * We print before the forms
225         * to avoid a FOUC
226         */
227        print Identity::getHtmlStyleTag(self::TAG);
228
229
230        $form->addClass(Identity::FORM_IDENTITY_CLASS . " " . self::FORM_LOGIN_CLASS);
231
232        /**
233         * Heading
234         */
235        $headerHTML = Identity::getHeaderHTML($form, self::FORM_LOGIN_CLASS);
236        if ($headerHTML != "") {
237            $form->addHTML($headerHTML, 1);
238        }
239
240        $brPositionElement = [4, 5]; // 4 and 6 but when you delete 4, it's on 5
241        foreach ($brPositionElement as $brPosition) {
242            $fieldBr = $form->getElementAt($brPosition);
243            if ($fieldBr->val() === "<br>\n") {
244                $form->removeElement($brPosition);
245            } else {
246                LogUtility::msg("Internal: the login br $brPosition element was not found and not deleted");
247            }
248        }
249
250        /**
251         * Fieldset delete
252         */
253        $elementsTypeToDelete = ["fieldsetopen", "fieldsetclose"];
254        foreach ($elementsTypeToDelete as $type) {
255            $field = $form->findPositionByType($type);
256            if ($field != false) {
257                $form->removeElement($field);
258            }
259        }
260
261        /**
262         * Field
263         */
264        $submitButtonPosition = $form->findPositionByAttribute("type", "submit");
265        if ($submitButtonPosition == false) {
266            LogUtility::msg("Internal error: No submit button found");
267            return;
268        }
269        /**
270         * This is important to keep the submit element intact
271         * for forms integration such as captcha
272         * They search the submit button to insert before it
273         */
274        $form->getElementAt($submitButtonPosition)
275            ->addClass("btn")
276            ->addClass("btn-primary")
277            ->addClass("btn-block")
278            ->addClass("mb-2");
279
280        $userPosition = $form->findPositionByAttribute("name", "u");
281        if ($userPosition == false) {
282            LogUtility::msg("Internal error: No user field found");
283            return;
284        }
285        /**
286         * @var InputElement $userField
287         */
288        $userField = $form->getElementAt($userPosition);
289        $newUserField = new InputElement($userField->getType(), "u");
290        $loginText = $userField->getLabel()->val();
291        foreach ($userField->attrs() as $keyAttr => $valueAttr) {
292            $newUserField->attr($keyAttr, $valueAttr);
293        }
294        $newUserField->addClass("form-control");
295        $newUserField->attr("placeholder", $loginText);
296        $newUserField->attr("required", "required");
297        $newUserField->attr("autofocus", "");
298        $userFieldId = $userField->attr("id");
299
300        $form->replaceElement($newUserField, $userPosition);
301
302        $form->addHTML("<div class=\"form-floating\">", $userPosition);
303        $form->addHTML("<label for=\"$userFieldId\">$loginText</label>", $userPosition + 2);
304        $form->addHTML("</div>", $userPosition + 3);
305
306
307        $pwdPosition = $form->findPositionByAttribute("name", "p");
308        if ($pwdPosition == false) {
309            LogUtility::msg("Internal error: No password field found");
310            return;
311        }
312        $pwdField = $form->getElementAt($pwdPosition);
313        $newPwdField = new InputElement($pwdField->getType(), "p");
314        foreach ($pwdField->attrs() as $keyAttr => $valueAttr) {
315            $newPwdField->attr($keyAttr, $valueAttr);
316        }
317        $newPwdField->addClass("form-control");
318        $passwordText = $pwdField->getLabel()->val();
319        $newPwdField->attr("placeholder", $passwordText);
320        $newPwdField->attr("required", "required");
321        $pwdFieldId = $newPwdField->attr("id");
322        if(empty($pwdFieldId)){
323            $pwdFieldId = "input__password";
324            $newPwdField->id($pwdFieldId);
325        }
326        $form->replaceElement($newPwdField, $pwdPosition);
327
328
329        $form->addHTML("<div class=\"form-floating\">", $pwdPosition);
330        $form->addHTML("<label for=\"$pwdFieldId\">$passwordText</label>", $pwdPosition + 2);
331        $form->addHTML("</div>", $pwdPosition + 3);
332
333
334        $rememberPosition = $form->findPositionByAttribute("name", "r");
335        if ($rememberPosition == false) {
336            LogUtility::msg("Internal error: No remember field found");
337            return;
338        }
339        $rememberField = $form->getElementAt($rememberPosition);
340        $newRememberField = new InputElement($rememberField->getType(), "r");
341        foreach ($rememberField->attrs() as $keyAttr => $valueAttr) {
342            $newRememberField->attr($keyAttr, $valueAttr);
343        }
344        $newRememberField->addClass("form-check-input");
345        $form->replaceElement($newRememberField, $rememberPosition);
346
347        $remberText = $rememberField->getLabel()->val();
348        $remFieldId = $newRememberField->attr("id");
349
350        $form->addHTML("<div class=\"form-check py-2\">", $rememberPosition);
351        $form->addHTML("<label for=\"$remFieldId\" class=\"form-check-label\">$remberText</label>", $rememberPosition + 2);
352        $form->addHTML("</div>", $rememberPosition + 3);
353
354
355
356//        $registerHtml = action_plugin_combo_registration::getRegisterLinkAndParagraph();
357//        if (!empty($registerHtml)) {
358//            $newFormContent[] = $registerHtml;
359//        }
360//
361//        $resendPwdHtml = action_plugin_combo_resend::getResendPasswordParagraphWithLinkToFormPage();
362//        if (!empty($resendPwdHtml)) {
363//            $newFormContent[] = $resendPwdHtml;
364//        }
365
366
367    }
368
369}
370