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