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