<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:py="http://genshi.edgewall.org/"
      xmlns:i18n="http://genshi.edgewall.org/i18n"
      i18n:domain="acct_mgr">
  <xi:include href="admin.html" />
  <head>
    <title>Accounts: Configuration</title>
    <script type="text/javascript"
            src="${chrome.htdocs_location}js/folding.js"></script>
    <script type="text/javascript">/*<![CDATA[*/
      jQuery(document).ready(function($) {
        // Hide configuration preview sections by default
        $("fieldset legend.foldable").enableFolding(true);
      });
    /*]]>*/</script>
  </head>

  <body>
    <div id="content" class="config">
      <h2>Accounts: Configuration</h2>
      <!-- Progress bar -->
      <ul id="progress">
        <li py:for="idx,step in enumerate(steps)"
            py:with="url = s_href=href.admin('accounts', 'config',
                                             step=idx != 0 and idx or None)"
            class="${step.past and 'past' or
                     (idx == active and 'active') or None}"
            id="${idx == len(steps) - 1 and 'last' or None}"
            style="${'width:' + str(100 / len(steps)) + '%'}">
          <span>
            <a href="$url">${idx + 1}</a>
          </span>
          <a href="$url" title="${step.image and step.label or None}">
          <img class="icon" alt="${step.label}" py:if="step.image"
               height="32" width="32"
               src="${href.chrome('/acct_mgr/' + step.image + '.png')}" />
          <py:if test="not step.image">$step.label</py:if>
          </a>
        </li>
      </ul>

      <form id="cfg_wiz" method="post"
            action="${href.admin('accounts', 'config')}">
        <!-- Top navigation -->
        <div class="buttons">
          <input type="submit" name="back"
                 py:if="active != 0 and active != (len(steps) - 1)"
                 title="${dgettext('acct_mgr', 'Apply changes and go back')}"
                 value="${dgettext('acct_mgr', 'Previous')}" />
          <input type="submit" name="prev" py:if="active == (len(steps) - 1)"
                 title="${dgettext('acct_mgr', 'Go back')}"
                 value="${dgettext('acct_mgr', 'Previous')}" />
          <input type="submit" name="next" py:if="active != (len(steps) - 1)"
                 title="${dgettext('acct_mgr', 'Apply changes and go on')}"
                 value="${dgettext('acct_mgr', 'Next')}" />
          <!-- Last value cache for stepping through pages back and forth -->
          <input type="hidden" name="active" value="$active" />
        </div>
        <py:choose test="active">

          <!--! Page 1 -->
          <fieldset py:when="0">
            <legend class="step" i18n:msg="step,label">
              Step ${str(active + 1)}: ${steps[active].label}
            </legend>
          <h3>Objective for setting Authentication Options</h3>
          <p>${
            dgettext("acct_mgr",
                     "Decide, whether to use HTTP authentication (Trac default) or a HTML login"
                     " form provided by AccountManagerPlugin.")
          }</p>
          <p>${
            dgettext("acct_mgr",
                     "After initial login Trac sessions are authenticated per request based on "
                     "browser cookies. Therefore a number of options provide control over some "
                     "critical browser cookie properties.")
          }</p>

          <h3>Provider-agnostic Authentication Options</h3>
          <div class="field">
            <label>
              <input type="checkbox" name="ignore_auth_case" value="true"
                     title="${'[trac] ignore_auth_case'}"
                     checked="${ignore_auth_case and 'checked' or None}" />
              Convert login names to lower case on registration and login.
            </label>
            <p class="hint" i18n:msg="">
              Adapt to careless username typing, where casing does not <!--!
           -->matter, like on Windows. Potentially troublesome, because <!--!
           --><tt>case matters for Trac permission assignment lookup</tt> anyway.
            </p>
          </div>
          <div class="field">
            <label>
              <input type="checkbox" name="check_auth_ip" value="true"
                     title="${'[trac] check_auth_ip'}"
                     checked="${check_auth_ip and 'checked' or None}" />
              Check IP address for authentication.
            </label>
            <p class="hint">${
              dgettext("acct_mgr",
                       "Potentially troublesome for users with dynamic IP address, but "
                       "disregarded for persistent sessions.")
            }</p>
          </div>
          <div class="field">
            <label>
              <input type="checkbox" name="secure_cookies" value="true"
                     title="${'[trac] secure_cookies'}"
                     checked="${secure_cookies and 'checked' or None}" />
              Restrict sending cookies to HTTPS connections.
            </label>
            <p class="hint">
              Required, if the Trac instance is only accessible through HTTPS.
            </p>
          </div>
          <div class="field">
            <!--! Last value cache for JS code -->
            <input type="hidden" id="auth_cookie_lifetime_old"
                   value="$auth_cookie_lifetime" disabled="disabled" />
            <label py:with="
                lifetime_value = ((auth_cookie_lifetime or 2592000)
                                  if acctmgr_login else auth_cookie_lifetime)
              ">${
              i18n_tag(
                dgettext("acct_mgr",
                         "Lifetime of the authentication cookie: [1:] seconds [2:(%(timedelta)s)]"),
                ('input', {'type': 'text', 'class': 'numwidget',
                           'name': 'auth_cookie_lifetime',
                           'title': '[trac] auth_cookie_lifetime',
                           'value': auth_cookie_lifetime}),
                ('span', {'class': 'hint',
                          'style': None if lifetime_value else 'display:none'}),
                timedelta=format_timespan(lifetime_value),
              )
            }</label>
            <p class="hint">${
              dgettext("acct_mgr",
                       "Determines how long the browser will cache authentication "
                       "information, and therefore, after how much inactivity a user will "
                       "have to log in again. Default (0 s) makes cookie expire at "
                       "browsing sessions end.")
            }</p>
          </div>

          <h3>Authentication Front-end</h3>
          <div class="field">
            <label>
              <input type="radio" name="acctmgr_login" value="0"
                     checked="${acctmgr_login and None or 'checked'}"
                     title="${'[components] trac.web.auth.loginmodule'}" />
              ${dgettext("acct_mgr",
                         "Use HTTP authentication and credentials as configured "
                         "in and provided by your web-server.")}
            </label>
            <p class="hint">${
              dgettext("acct_mgr",
                       "You can still manage some password stores with "
                       "AccountManagerPlugin, if you configure them in the next step.")
            }</p>
            <label>
              <input type="radio" name="acctmgr_login" value="1"
                     checked="${acctmgr_login and 'checked' or None}"
                     title="${'[components] acct_mgr.web_ui.loginmodule'}" />
              ${dgettext("acct_mgr",
                         "Use a HTML login form backed by one or more "
                         "password stores managed by AccountManagerPlugin.")}
            </label>
            <p class="hint" i18n:msg="">
              AccountManagerPlugin provides a custom version of the <!--!
           --><strong>LoginModule</strong> accompanied by a form-based <!--!
           -->HTML login page.
            </p>
            <p class="hint" i18n:msg="">
              If you enable this feature, you'll want to review and adjust <!--!
           -->some more options related to session authentication. <!--!
           -->Note, that AccountManagerPlugin's LoginModule <tt>changes <!--!
           -->the default lifetime of authentication cookies to 30 days</tt>.
            </p>
          </div>

          <div id="acctmgr_login_opts">
            <h3>AccountManagerPlugin Authentication Options</h3>
            <div class="field">
              <label>
                <input type="checkbox" name="login_opt_list" value="true"
                       checked="${login_opt_list and 'checked' or None}"
                       title="${'[account-manager] login_opt_list'}" />
                Integrate links to related actions into the login form.
              </label>
              ${
                i18n_tag(
                  dgettext(
                    "acct_mgr",
                    "[1:If enabled, links to][2:[3:[4:Lost password/Password "
                    "reset]][5:[6:Registration for new users]]][7:that normally reside in "
                    "Trac's meta-navigation bar, will appear inside the login form. CSS "
                    "styling allows further customization of the login prompt.]"
                  ),
                  ('p', {'class': 'hint'}), 'ul',
                  'li', ('span', {'class': 'hint'}),
                  'li', ('span', {'class': 'hint'}),
                  ('p', {'class': 'hint'}),
                )
              }
            </div>
            <div class="field">
              <label>
                <input type="checkbox" name="persistent_sessions" value="true"
                       checked="${persistent_sessions and 'checked' or None}"
                       title="${'[account-manager] persistent_sessions'}" />
                ${dgettext("acct_mgr",
                           "Allow the user to be remembered across sessions "
                           "without needing to re-authenticate.")}
              </label>
              <p class="hint" i18n:msg="">
                This is, user checks a "Remember Me" <tt>checkbox</tt> in <!--!
             -->the AccountManagerPlugin login form and, next time he <!--!
             -->visits the site within 30 days, he'll be remembered and <!--!
             -->authenticated automatically.
              </p>
            </div>
            <div class="field">
              <label i18n:msg="">
                Likelihood of session cookie ID change: <!--!
             --><input type="text" class="numwidget" name="cookie_refresh_pct"
                       title="${'[account-manager] cookie_refresh_pct'}"
                       value="$cookie_refresh_pct" /> <!--!
             -->% per work hour
              </label>
              <p class="hint" i18n:msg="">
                Driving a refresh process to decrease vulnerability of <!--!
             -->long-lasting sessions. Zero means <strong>never</strong>.
              </p>
            </div>
            <div class="field">
              <label>
                Path for authentication cookie:
                <input type="text" class="textwidget" name="auth_cookie_path"
                       title="${'[trac] auth_cookie_path'}"
                       value="$auth_cookie_path" />
              </label>
              <p class="hint" i18n:msg="">
                This enables AccountManagerPlugin's authentication data <!--!
             -->distribution to Trac instances with matching cookie path. <!--!
             -->Set this to a common base path of several Trac instances <!--!
             -->to share the cookie, providing a cheap <!--!
             --><tt>Single-Sign-On</tt> experience.
              </p>
            </div>
          </div>
          </fieldset>

          <!--! Page 2 -->
          <fieldset py:when="1">
            <legend class="step" i18n:msg="step,label">
              Step ${str(active + 1)}: ${steps[active].label}
            </legend>
            <img class="icon" alt="Password store" src="${href.chrome('/acct_mgr/users.png')}" />

            <h3>Objective for configuring a Password Store</h3>
            <p>${
              dgettext("acct_mgr",
                       "AccountManagerPlugin manages user credentials in a modular "
                       "back-end providing access to at least one password store.")
            }</p>

            <div py:if="len(password_store) == 0">
              <h3>Initial Authentication Back-end selection</h3>
              <!-- Initial setup content -->
              <div class="field">
                <label>
                  <input type="radio" name="init_store" value="db"
                         checked="${'checked' if init_store == 'db' else None}"
                         title="${'[account-manager] password_store'}" />
                  Use a password store embedded into Trac db.
                </label>
                <p class="hint" i18n:msg="">
                  The <strong>SessionStore</strong> implements password <!--!
               -->storage in Trac db table 'session_attribute'. Its the <!--!
               -->default choice mainly for avoiding additional dependencies <!--!
               -->like directory and file permissions.
                </p>
                <p class="hint">${
                  dgettext(
                    "acct_mgr",
                    "While great to resolve some concurrent access issues too, "
                    "this password store has shortcomings as well. Notably it "
                    "does not support seamless hash type migration, and its no "
                    "candidate for shared use by multiple Trac instances or even "
                    "by applications beyond Trac.")
                }</p>
                <fieldset class="ini" id="db">
                  <legend class="foldable">Details (Preview)</legend>
                  <div class="compact">
                    <pre>$init_store_hint.db</pre>
                    <p class="hint">${
                      dgettext("acct_mgr",
                               "Please apply these default options first. "
                               "You'll be able to change values afterwards.")
                    }</p>
                  </div>
                </fieldset>
              </div>
              <div class="field">
                <label>
                  <input type="radio" name="init_store" value="file"
                         checked="${'checked' if init_store in ('htdigest', 'htpasswd') else None}" />
                  Use a file-based password store.
                </label>
                <p class="hint">${
                  dgettext("acct_mgr",
                           "AccountManagerPlugin includes native support for common "
                           "Apache file formats 'htpasswd' and 'htdigest' as well as "
                           "support for reading svnserve's password file format.")
                }</p>
                <p class="hint">${
                  dgettext("acct_mgr",
                           "You may use the same file for several Trac environments. "
                           "Note that setting appropriate directory and file permissions "
                           "is crucial for these stores, but not covered by this "
                           "configuration wizard.")
                }</p>
              </div>
              <fieldset id="init_store_file">
                <div class="field">
                  <label>
                    <input type="radio" name="init_store_file" value="htdigest"
                           checked="${'checked' if init_store == 'htdigest' or not htpasswd else None}"
                           title="${'[account-manager] password_store'}" />
                    <i18n:msg>
                      'htdigest' format <span class="hint">(<strong>HtDigestStore</strong>)</span>
                    </i18n:msg>
                  </label>
                  <fieldset class="ini" id="htdigest">
                    <legend class="foldable">Details (Preview)</legend>
                    <div class="compact">
                      <pre>$init_store_hint.htdigest</pre>
                      <p class="hint">${
                        dgettext("acct_mgr",
                                 "Please apply these default options first. "
                                 "You'll be able to change values afterwards.")
                      }</p>
                    </div>
                  </fieldset>
                </div>
                <div class="field">
                  <label>
                    <input type="radio" name="init_store_file"
                           value="htpasswd"
                           checked="${'checked' if init_store == 'htpasswd' else None}"
                           title="${'[account-manager] password_store'}" />
                    <i18n:msg>
                      'htpasswd' format <span class="hint">(<strong>HtPasswdStore</strong>)</span>
                    </i18n:msg>
                  </label>
                  <fieldset class="ini" id="htpasswd">
                    <legend class="foldable">Details (Preview)</legend>
                    <div class="compact">
                      <pre>$init_store_hint.htpasswd</pre>
                      <p class="hint">${
                        dgettext("acct_mgr",
                                 "Please apply these default options first. "
                                 "You'll be able to change values afterwards.")
                      }</p>
                    </div>
                  </fieldset>
                </div>
                <div class="field">
                  <label>
                    <input type="radio" name="init_store_file"
                           value="svn_file"
                           checked="${'checked' if init_store == 'svn_file' else None}"
                           title="${'[account-manager] password_store'}" />
                    <i18n:msg>
                      svnserve's password file format <span
                        class="hint">(<strong>SvnServePasswordStore</strong>)</span>
                    </i18n:msg>
                  </label>
                  <fieldset class="ini" id="svn_file">
                    <legend class="foldable">Details (Preview)</legend>
                    <div class="compact">
                      <pre>$init_store_hint.svn_file</pre>
                      <p class="hint">${
                        dgettext("acct_mgr",
                                 "Please apply these default options first. "
                                 "You'll be able to change values afterwards.")
                      }</p>
                    </div>
                  </fieldset>
                </div>
              </fieldset>
              <div class="field">
                <label>
                  <input type="radio" name="init_store" value="http"
                         checked="${init_store == 'http' and
                                    'checked' or None}"
                         title="${'[account-manager] password_store'}" />
                  Delegate authentication using HTTP authentication.
                </label>
                <p class="hint" i18n:msg="">
                  AccountManagerPlugin enables use of standard HTTP-Auth <!--!
               -->by its <strong>HttpAuthStore</strong> component. Both <!--!
               -->Basic and Digest authentication challenges are supported.
                </p>
                <p class="hint">${
                  dgettext("acct_mgr",
                           "In addition to being read-only this password store does "
                           "not even support listing users for obvious reasons.")
                }</p>
                <fieldset class="ini" id="http">
                  <legend class="foldable">Details (Preview)</legend>
                  <div class="compact">
                    <pre>$init_store_hint.http</pre>
                    <p class="hint">${
                      dgettext("acct_mgr",
                               "Please apply these default options first. "
                               "You'll be able to change values afterwards.")
                    }</p>
                  </div>
                </fieldset>
              </div>

              <div class="field">
                <label>
                  <!-- Disabled to speed-up initial publication -->
                  <input type="radio" name="init_store" value="etc"
                         checked="${init_store == 'etc' and
                                    'checked' or None}"
                         disabled="disabled"
                         title="${'[account-manager] password_store'}" />
                  Use a different password store.
                </label>
                <p class="hint">${
                  dgettext(
                    "acct_mgr",
                    "AccountManagerPlugin's modular password store concept "
                    "encourages creation of more ways to provide user credential "
                    "beyond the natively supported stores. While a specific setup "
                    "assistance for these 3rd-party authentication providers is not "
                    "implemented, you may fill-in appropriate configuration details "
                    "for an already installed component below.")
                }</p>
              </div>
              <fieldset id="etc_store_cfg">
                <legend>Configuration</legend>
                <div class="compact field">
                  <textarea name="etc_cfg">$init_store_hint.http</textarea>
                  <p class="hint">${
                    dgettext("acct_mgr",
                             "Type the custom configuration options as provided by "
                             "that components documentation and apply it.")
                  }</p>
                </div>
              </fieldset>
            </div>

            <div py:if="len(password_store) > 0">
              <!-- Standard page content -->
              <h3>Password Store Configuration</h3>
              <p i18n:msg="store_list">
                All enabled stores are listed below, but most won't work at <!--!
                -->all without additional configuration.<br />Currently configured: <!--!
                --><em title="${'[account-manager] password_store'}">${', '.join(password_store)}</em>
              </p>
              <p class="hint" py:if="len(password_store) > 1">
                This is an experts-only type of store configuration.
              </p>
              <div class="system-message" py:if="disabled_store">
                <p>
                  <strong i18n:msg="components">
                    Required disabled component(s): <em>${', '.join(disabled_store)}</em>
                  </strong>
                </p>
              </div>
              <p>${
                dgettext("acct_mgr",
                         "Select one or more stores and configure related options. "
                         "Concurrent use of multiple password stores is supported too.")
              }</p>
              <p class="hint">
                Password stores are queried in turn, so order matters.
              </p>

              <fieldset py:for="section in store_list">
                <legend>
                  <label>
                    <select name="${section.classname}" >
                      <option py:for="order in store_count" value="${order}"
                              selected="${order == section.order or None}">
                        ${order == 0 and '--' or order}
                      </option>
                    </select>
                    $section.name
                  </label>
                </legend>
                <div class="field" py:for="option in section.options">
                  <label>$option.label:
                    <py:choose>
                      <div class="system-message"
                           py:when="isinstance(option.value, dict) and
                                    'error' in option.value.keys()" >
                        <p>${option.value['error']}</p>
                      </div>
                      <select name="$option.name"
                              py:when="isinstance(option.value, dict)" >
                        <option py:for="opt in option.value['options']"
                                class="textwidget"
                                selected="${opt == option.value['selected'] or None}"
                                value="${opt}">
                          ${opt}
                        </option>
                      </select>
                      <input type="text" class="textwidget" py:otherwise=""
                             name="$option.name" value="$option.value" />
                    </py:choose>
                  </label>
                  <p class="hint" py:if="option.doc">$option.doc</p>
                </div>
              </fieldset>

              <div class="field">
                <label>
                  <input type="checkbox" name="refresh_passwd" value="true"
                         checked="${refresh_passwd and 'checked' or None}"
                         title="${'[account-manager] refresh_passwd'}" />
                  Silently update password hashes on next successful login.
                </label>
                <p class="hint">${
                  dgettext("acct_mgr",
                           "Use it after changing hash type or to migrate to a new "
                           "primary password store.")
                }</p>
                <p class="hint">${
                  dgettext("acct_mgr",
                           "The update will run only once. Restarting the procedure "
                           "for all accounts allows to propagate subsequent changes.")
                }</p>
                <div class="buttons">
                  <input type="submit" name="restart" id="restart"
                         value="${dgettext('acct_mgr', 'Restart')}" />
                </div>
              </div>
            </div>
          </fieldset>

          <!--! Page 3 -->
          <fieldset py:when="2">
            <legend class="step" i18n:msg="step,label">
              Step ${str(active + 1)}: ${steps[active].label}
            </legend>
            <img class="icon" alt="Password refresh" src="${href.chrome('/acct_mgr/refresh.png')}" />

            <h3>Objective for Password Policy rules</h3>
            <p>${
              dgettext("acct_mgr",
                       "While AccountManagerPlugin does not enforce password rules in "
                       "general, there are some other ways to alter password handling.")
            }</p>

            <div class="field">
              <label>
                <input type="checkbox" name="reset_password" value="true"
                       checked="${reset_password and 'checked' or None}"
                       title="${'[account-manager] reset_password'}" />
                Enable the password reset procedure.
              </label>
              <p class="hint">${
                dgettext("acct_mgr",
                         "It relies on a working email sender for Trac, supporting "
                         "both TracAnnouncer and TracNotification.")
              }</p>
            </div>
            <div class="field">
              <label i18n:msg="">
                Length of the randomly-generated passwords: <input
                  type="text" class="numwidget" name="generated_password_length"
                  title="${'[account-manager] generated_password_length'}"
                  value="$generated_password_length" /> characters
              </label>
              <p class="hint">
                These passwords are used as alternative passwords on request.
              </p>
            </div>
            <div class="field">
              <label>
                <input type="checkbox" name="force_passwd_change" value="true"
                       checked="${force_passwd_change and 'checked' or None}"
                       title="${'[account-manager] force_passwd_change'}" />
                Force users to change passwords after a password reset.
              </label>
            </div>
          </fieldset>

          <!--! Page 4 -->
          <fieldset py:when="3">
            <legend class="step" i18n:msg="step,label">
              Step ${str(active + 1)}: ${steps[active].label}
            </legend>
            <img class="icon" alt="Account approval" src="${href.chrome('/acct_mgr/approval.png')}" />

            <h3>Objective for Account Registration and Verification rules</h3>
            <p>${
              dgettext(
                "acct_mgr",
                "You may require administrative approval of new accounts for the user "
                "registration process. The ability to immediately ban existing accounts is"
                " another, related but independent feature.")
            }</p>
            <div class="field">
              <label>
                <input type="checkbox" name="change_uid_enabled"
                       checked="${change_uid_enabled and 'checked' or None}"
                       title="${'[components] acct_mgr.model.*'}"
                       value="true" />
                Allow administrative user ID changes.
              </label>
            </div>
            <div class="field">
              <label>
                <input type="checkbox" name="acctmgr_register"
                       checked="${acctmgr_register and 'checked' or None}"
                       title="${'[components] acct_mgr.register.RegistrationModule'}"
                       value="true" />
                Allow users to register for a new account.
              </label>
            </div>
            <div class="field">
              <label>
                <input type="checkbox" name="allow_delete_account"
                       checked="${allow_delete_account and 'checked' or None}"
                       title="${'[account-manager] allow_delete_account'}"
                       value="true" />
                Allow users to delete their own account.
              </label>
            </div>

            <h3>Checks to use for validating Registration requests</h3>
            <p i18n:msg="check_list">
              All checks provided by AccountManagerPlugin are enabled per <!--!
              -->default, but some are configurable on their own.<br /><!--
              -->Currently configured: <!--!
              --><em title="${'[account-manager] register_check'}">${', '.join(register_check)}</em>
            </p>
            <p class="hint" i18n:msg="">
              Checks like <strong>BotTrapCheck</strong> won't work at all <!--!
           -->without additional configuration.
            </p>
            <div class="system-message" py:if="disabled_check">
              <p>
                <strong i18n:msg="components">
                  Required disabled component(s): <em>${', '.join(disabled_check)}</em>
                </strong>
              </p>
            </div>
            <p>${
              dgettext(
                "acct_mgr",
                "Select one or more checks and configure related options. "
                "Concurrent use of multiple registration checks is encouraged.")
            }</p>
            <p class="hint">${
              dgettext(
                "acct_mgr",
                "Checks are applied in turn, so order matters. Note that some "
                "checks are used to validate admin user actions too.")
            }</p>

            <fieldset py:for="section in check_list">
              <legend>
                <label>
                  <select name="${section.classname}" >
                    <option py:for="order in check_count" value="${order}"
                            selected="${order == section.order or None}">
                      ${order == 0 and '--' or order}
                    </option>
                  </select>
                  $section.name
                </label>
              </legend>
              <div py:if="section.doc" xml:space="preserve">
                ${safe_wiki_to_html(context, section.doc)}
              </div>
              <div class="field" py:for="option in section.options">
                <label>$option.label:
                  <py:choose>
                    <div class="system-message"
                         py:when="isinstance(option.value, dict) and
                                  'error' in option.value.keys()" >
                      <p>${option.value['error']}</p>
                    </div>
                    <select name="$option.name"
                            py:when="isinstance(option.value, dict)" >
                      <option py:for="opt in option.value['options']"
                              class="textwidget"
                              selected="${opt == option.value['selected'] or
                                          None}"
                              value="${opt}">
                        ${opt}
                      </option>
                    </select>
                    <input type="text" class="textwidget" py:otherwise=""
                           name="$option.name" value="$option.value" />
                  </py:choose>
                </label>
                <p class="hint" py:if="option.doc">$option.doc</p>
              </div>
            </fieldset>

            <h3>Other Account Policy options</h3>
            <div id="acctmgr_register_opts">
              <div class="field">
                <label>
                  <input type="checkbox" name="require_approval" value="true"
                         checked="${require_approval and 'checked' or None}"
                         title="${'[account-manager] require_approval'}" />
                  Require administrative account approval after registration.
                </label>
                <p class="hint">${
                  dgettext(
                    "acct_mgr",
                    "For admin notification on registration time it relies on a "
                    "working email sender for Trac, supporting both TracAnnouncer "
                    "and TracNotification.")
                }</p>
              </div>
            </div>
            <div class="field">
              <label>
                <input type="checkbox" name="verify_email" value="true"
                       checked="${verify_email and 'checked' or None}"
                       title="${'[account-manager] verify_email'}" />
                Force users to verify their email addresses.
              </label>
              <p class="hint">${
                dgettext(
                  "acct_mgr",
                  "For sending a verification token to the user it relies on a working email "
                  "sender for Trac, supporting both TracAnnouncer and TracNotification.")
              }</p>
            </div>
          </fieldset>

          <!--! Page 5 -->
          <fieldset py:when="4">
            <legend class="step" i18n:msg="step,label">
              Step ${str(active + 1)}: ${steps[active].label}
            </legend>
            <img class="icon" alt="Account guard" src="${href.chrome('/acct_mgr/guard.png')}" />

            <h3>Objective for Account Protection rules</h3>
            <p>${
              dgettext(
                "acct_mgr",
                "Passwords are often not constructed as carefully as they should "
                "be. And even a strong passphrase could be sift out, if an "
                "attacker is able to test millions of variants in hours, if not "
                "seconds. Firewalls and full-featured web-servers already offer "
                "sophisticated protection, if one can afford them, handle their "
                "installation, configuration and maintenance.")
            }</p>
            <p i18n:msg="">
              The <strong>AccountGuard</strong> component is another option. <!--!
           -->It is an add-on to AccountManagerPlugin's own <!--!
           --><strong>LoginModule</strong> and provides account protection <!--!
           -->by discouraging brute-force login attempts.
            </p>

            <div class="field">
              <label>
                <input type="checkbox" name="acctmgr_guard"
                       checked="${acctmgr_guard and 'checked' or None}"
                       disabled="${not acctmgr_login and 'disabled' or None}"
                       title="${'[components] acct_mgr.guard.AccountGuard'}"
                       value="true" />
                Enable the guard add-on component.
              </label>
              <p class="hint" py:if="not acctmgr_login">
                AccountManagerPlugin's LoginModule is disabled.
              </p>
            </div>
            <div id="acctmgr_guard_opts">
              <div class="field">
                <label>
                  Failed login attempt count max:
                  <input type="text" class="numwidget"
                         name="login_attempt_max_count"
                         title="${'[account-manager] login_attempt_max_count'}"
                         value="$login_attempt_max_count" />
                </label>
                <p class="hint" i18n:msg="">
                  Lock user account after the specified number of failed <!--!
                  -->attempts. Value zero means <strong>no limit</strong>.
                </p>
              </div>
              <div id="user_lock_time">
                <div class="field">
                  <label i18n:msg="">
                    Drop lock after <input
                      type="text" class="numwidget" name="user_lock_time"
                      title="${'[account-manager] user_lock_time'}"
                      value="$user_lock_time" /> seconds
                  </label>
                  <p class="hint" i18n:msg="">
                    Zero means <strong>unlimited</strong> lock time here.
                  </p>
                </div>
                <div id="user_lock_time_progression">
                  <div class="field">
                    <label>
                      Lock time progression factor:
                      <input type="text" class="numwidget"
                             name="user_lock_time_progression"
                             title="${'[account-manager] user_lock_time_progression'}"
                             value="$user_lock_time_progression" />
                    </label>
                    <p class="hint">${
                      dgettext("acct_mgr",
                              "Extend user account lock duration incrementally. "
                              "It uses logarithmic calculation with the factor as "
                              "exponent, accepting decimal numbers >= 1.")
                    }</p>
                    ${
                      i18n_tag(
                        dgettext(
                          "acct_mgr",
                          "[1:Lock time will grow for any value > 1, if the failure happens before "
                          "lock expiration. I.e. value '2' means][2:[3:[4:double lock time after 2nd"
                          " failure,]][5:[6:four times the initial lock time after 3rd,]][7:[8:eight"
                          " times as long after 4th failure, etc.]]]"),
                        ('p', {'class': 'hint'}),
                        'ul',
                        'li', ('span', {'class': 'hint'}),
                        'li', ('span', {'class': 'hint'}),
                        'li', ('span', {'class': 'hint'}),
                      )
                    }
                    <p class="hint">${
                      dgettext("acct_mgr",
                               "At any time after lock expiration a login failure will "
                               "just trigger a lock and set a new lock timeout, but not "
                               "extend the total lock duration.")
                    }</p>
                  </div>
                  <!--! Last value cache for JS code -->
                  <input type="hidden" id="user_lock_max_time_old"
                         value="$user_lock_max_time" disabled="disabled" />
                  <div id="user_lock_max_time" class="field">
                    <label py:with="
                      ">${
                      i18n_tag(
                        dgettext("acct_mgr",
                                 "Upper lock time limit: [1:] seconds [2:(%(time)s)]"),
                        ('input', {'type': 'text', 'class': 'numwidget',
                                   'name': 'user_lock_max_time',
                                   'title': '[account-manager] user_lock_max_time',
                                   'value': user_lock_max_time}),
                        ('span', {'class': 'hint',
                                  'style': None if user_lock_max_time else 'display:none'}),
                        time=format_timespan(user_lock_max_time) if user_lock_max_time else '', \
                      )
                    }</label>
                    <p class="hint">
                      This is relevant only with a progression factor > 1.
                    </p>
                  </div>
                </div>
              </div>
            </div>
          </fieldset>

          <!--! Page 6 -->
          <fieldset py:otherwise="">
            <legend class="step" i18n:msg="step,label">
              Step ${str(active + 1)}: ${steps[active].label}
            </legend>
            <div py:if="not admin_available">
              <h3>Objective for additional preparation</h3>
              <p>Enable yourself to proceed beyond this initial setup.</p>
              <h3>Initial Admin Account</h3>
              <fieldset>
                <legend>Add Admin Account:</legend>
                <p i18n:msg="">
                  The user will get <strong>TRAC_ADMIN</strong> assigned, <!--!
               -->that inherits all available permissions. One such <!--!
               -->account is required to configure Trac via the admin <!--!
               -->web-UI. Create and manage more limited admin accounts <!--!
               -->as well as actual user accounts on your own later via <!--!
               -->the Accounts admin panel.
                </p>
                <p class="hint" i18n:msg="">
                  In detail: AccountManagerPlugin requires <!--!
               --><strong>ACCTMGR_USER_ADMIN</strong> for regular user <!--!
               -->administration, <strong>ACCTMGR_CONFIG_ADMIN</strong> <!--!
               -->for viewing these pages and changing the configuration <!--!
               -->later. Both are inherited by <!--!
               --><strong>ACCTMGR_ADMIN</strong> permission. To assign <!--!
               -->permissions you'll need <strong>PERMISSION_GRANT</strong> <!--!
               -->inherited by <strong>PERMISSION_ADMIN</strong> too.
                </p>
                <div class="field">
                  <label>Username:<br />
                    <input type="text" class="textwidget" id="username"
                           name="username" value="$acctmgr.username" />
                  </label>
                  <p class="hint" py:if="ignore_auth_case">
                    Only lowercase usernames allowed
                  </p>
                </div>
                <div class="field">
                  <label>Password:<br />
                    <input type="password" class="textwidget" name="password"
                           disabled="${None if set_password else 'disabled'}" />
                  </label>
                </div>
                <div class="field">
                  <label >Confirm Password:<br />
                    <input type="password" class="textwidget"
                           name="password_confirm"
                           disabled="${None if set_password else 'disabled'}" />
                  </label>
                </div>
                <p py:if="not password_store">${
                  dgettext("acct_mgr",
                           "Please take care, that the username is known by "
                           "the HTTP authentication provider.")
                }</p>
                <p py:if="password_store and not set_password">${
                  dgettext("acct_mgr",
                           "Please take care for a valid username, because no configured "
                           "password store supports creating a new account.")
                }</p>
                <div class="buttons">
                  <input type="submit" name="add" value="${dgettext('acct_mgr', ' Add ')}" />
                </div>
              </fieldset>
            </div>
            <h3>Check-up</h3>
            <ul>
              <li py:for="goal in completion.details" class="$goal.status">
                <a href="${href.admin('accounts', 'config', step=goal.step)}"
                   py:strip="not goal.step">
                  $goal.desc
                </a>
              </li>
            </ul>
            <p class="hint" py:if="admin_available and not completion.ready">
              Please resolve all issues marked as critical.
            </p>
            <div py:if="completion.ready">
              <p i18n:msg="">
                By now you did almost finish AccountManagerPlugin <!--!
             -->configuration, but any changes are temporary yet. Please <!--!
             -->test and adjust the configuration as required, or cancel <!--!
             -->to revert all changes. Apply settings to <!--!
             --><em>trac.ini</em> only if you really want to preserve <!--!
             -->them permanently.
              </p>
              <!--! Final configuration preview listing -->
              <fieldset>
                <legend class="foldable">Details (Preview)</legend>
                <div class="ini">
                  <py:for each="section in sorted(roundup)">
                    [$section]<br />
                    <py:for each="option, value in sorted(roundup[section])">
                      <span class="${'defaults'
                                     if option in roundup_defaults.get(section, {}) else
                                     None}"
                            >${option} = ${value}</span><br />
                    </py:for>
                    <br />
                  </py:for>
                </div>
              </fieldset>
            </div>
          </fieldset>
        </py:choose>

        <!-- Bottom navigation -->
        <div class="buttons">
          <input py:if="active != 0 and active != (len(steps) - 1)"
                 type="submit" name="back"
                 title="${dgettext('acct_mgr', 'Apply changes and go back')}"
                 value="${dgettext('acct_mgr', 'Previous')}" />
          <input py:if="active == (len(steps) - 1)"
                 type="submit" name="prev"
                 title="${dgettext('acct_mgr', 'Go back')}"
                 value="${dgettext('acct_mgr', 'Previous')}" />
          <input py:if="active != (len(steps) - 1)"
                 type="submit" name="save"
                 title="${dgettext('acct_mgr', 'Stay on page')}"
                 value="${dgettext('acct_mgr', 'Apply changes')}" />
          <input py:if="active == (len(steps) - 1)"
                 type="submit" name="save"
                 title="${dgettext('acct_mgr', 'Save changes and exit wizard')}"
                 value="${dgettext('acct_mgr', 'Apply changes')}"
                 disabled="${not completion.ready and 'disabled' or None}" />
          <input py:if="active != (len(steps) - 1)"
                 type="submit" name="reset"
                 title="${dgettext('acct_mgr', 'Drop unsaved changes')}"
                 value="${dgettext('acct_mgr', 'Refresh')}" />
          <input py:if="active != (len(steps) - 1)"
                 type="submit" name="next"
                 title="${dgettext('acct_mgr', 'Apply changes and go on')}"
                 value="${dgettext('acct_mgr', 'Next')}" />
          <input py:if="active == (len(steps) - 1)"
                 type="submit" name="exit"
                 title="${dgettext('acct_mgr', 'Drop changes and exit wizard')}"
                 value="${dgettext('acct_mgr', 'Cancel')}" />
        </div>
      </form>
    </div>
  </body>
</html>
