Mercurial > p > roundup > code
diff doc/customizing.txt @ 8416:370689471a08 issue2550923_computed_property
merge from default branch accumulated changes since Nov 2023
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sun, 17 Aug 2025 16:12:25 -0400 |
| parents | 14a8e11f3a87 0663a7bcef6c |
| children |
line wrap: on
line diff
--- a/doc/customizing.txt Sun Nov 05 11:38:18 2023 -0500 +++ b/doc/customizing.txt Sun Aug 17 16:12:25 2025 -0400 @@ -94,7 +94,7 @@ <tr> <th>Due Date</th> - <td tal:content="structure python:context.due_date.field(format='%Y-%m-%d')" /> + <td tal:content="structure python:context.due_date.field(display_time=False)" /> </tr> 3. Add the property to the ``issue.index.html`` page:: @@ -803,6 +803,11 @@ <table class="messages"> +The wiki includes an `auditor that extracts specially formatted timelog +entries from emails`_ sent to the tracker. + +.. _auditor that extracts specially formatted timelog + entries from emails: https://wiki.roundup-tracker.org/TimelogAuditor Tracking different types of issues ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1095,6 +1100,11 @@ username = self.db.user.get(self.userid, 'username') # now verify the password supplied against the LDAP store +Other External Databases +~~~~~~~~~~~~~~~~~~~~~~~~ + +See examples for `Shibboleth`_ and info about using `OAUTH`_ in the +Roundup Wiki. Changes to Tracker Behaviour ---------------------------- @@ -1871,6 +1881,60 @@ you could search for all currently-Pending users and do a bulk edit of all their roles at once (again probably with some simple javascript help). +.. _sensitive_changes: + +Confirming Users Making Sensitive Account Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some changes to account data: user passwords or email addresses are +particularly sensitive. The `OWASP Authentication`_ recommendations +include asking for a re-authentication or confirmation step when making +these changes. This can be easily implemented using an auditor. + +Create a file in your detectors directory with the following +contents:: + + from roundup.cgi.exceptions import Reauth + + def confirmid(db, cl, nodeid, newvalues): + + if hasattr(db, 'reauth_done'): + # the user has confirmed their identity + return + + # if the password or email are changing, require id confirmation + if 'password' in newvalues: + raise Reauth('Add an optional message to the user') + + if 'address' in newvalues: + raise Reauth('Add an optional message to the user') + + def init(db): + db.user.audit('set', confirmid, priority=110) + +If a change is made to any user's password or address fields, the user +making the change will be shown a page where they have to enter an +identity verifier (by default the invoking user's account password). +If the verifier is successfully verified it will set the +``reauth_done`` attribute on the db object and reprocess the change. + +The default auditor priority is 100. This auditor is set to run +**after** most other auditors. This allows the user to correct any +failing information on the form before being asked to confirm their +identity. Once they confirm their identity the change is expected to +be committed without issue. See :ref:`Confirming the User` for +details on customizing the verification operation. + +Also you could use an existing auditor and add:: + + if 'someproperty' in newvalues and not hasattr(db, 'reauth_done'): + raise Reauth('Need verification before changing someproperty') + +at the end of the auditor (after all checks are done) to force user +verification. Just make sure you import Reauth at the top of the file. + +.. _`OWASP Authentication`: + https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#require-re-authentication-for-sensitive-features Changes to the Web User Interface --------------------------------- @@ -1878,17 +1942,26 @@ Adding action links to the index page ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Add a column to the ``item.index.html`` template. +Add a column to the ``item.index.html`` template. In that column add +a form to trigger the action. Note: the form must use the POST method +for security. Resolving the issue:: - <a tal:attributes="href - string:issue${i/id}?:status=resolved&:action=edit">resolve</a> + <form method="POST" tal:attributes="action string:issue${i/id}"> + <button tal:replace="structure + python:context.submit(label='resolve', action='edit')" /> + <input type="hidden" name="status" value="resolved"> + </form> "Take" the issue:: - <a tal:attributes="href - string:issue${i/id}?:assignedto=${request/user/id}&:action=edit">take</a> + <form method="POST" tal:attributes="action string:issue${i/id}"> + <button tal:replace="structure + python:context.submit(label='take', action='edit')" /> + <input type="hidden" name="assignedto" + tal:attributes="value request/user/id"> + </form> ... and so on. @@ -1921,43 +1994,82 @@ ``issue.index.html``: 1. add a form around the listing table (separate from the existing - index-page form), so at the top it reads:: - - <form method="POST" tal:attributes="action request/classname"> - <table class="list"> - - and at the bottom of that table:: + index-page form), so at the top it reads: + + .. tabs:: + + .. code-tab:: html TAL + + <form method="POST" tal:attributes="action request/classname"> + <table class="list"> + + .. code-tab:: html Jinja2 + + <form method="POST" action='issue{{ context.id }}' class='form-inline'> + <table class="list"> + + + and at the bottom of that table add:: </table> - </form + </form> making sure you match the ``</table>`` from the list table, not the navigation table or the subsequent form table. -2. in the display for the issue property, change:: - - <td tal:condition="request/show/status" - tal:content="python:i.status.plain() or default"> </td> - - to:: - - <td tal:condition="request/show/status" - tal:content="structure i/status/field"> </td> - +2. in the display for the issue property, change: + + .. tabs:: + + .. code-tab:: html TAL + + <td tal:condition="request/show/status" + tal:content="python:i.status.plain() or default"> </td> + + .. code-tab:: html Jinja2 + + {% if request.show.status %} + <td>{{ issue.status.plain()|u }}</td> + {% endif %} + + to: + + .. tabs:: + + .. code-tab:: html TAL + + <td tal:condition="request/show/status" + tal:content="structure i/status/field"> </td> + + .. code-tab:: html Jinja2 + + {% if request.show.status %} + <td>{{ issue.status.menu()|u|safe }}</td> + {% endif %} + <!-- untested --> + this will result in an edit field for the status property. 3. after the ``tal:block`` which lists the index items (marked by - ``tal:repeat="i batch"``) add a new table row:: - - <tr> - <td tal:attributes="colspan python:len(request.columns)"> - <input name="@csrf" type="hidden" - tal:attributes="value python:utils.anti_csrf_nonce()"> - <input type="submit" value=" Save Changes "> - <input type="hidden" name="@action" value="edit"> - <tal:block replace="structure request/indexargs_form" /> - </td> - </tr> + ``tal:repeat="i batch"``) add a new table row: + + .. tabs:: + + .. code-tab:: html TAL + + <tr> + <td tal:attributes="colspan python:len(request.columns)"> + <input name="@csrf" type="hidden" + tal:attributes="value python:utils.anti_csrf_nonce()"> + <input type="submit" value=" Save Changes "> + <input type="hidden" name="@action" value="edit"> + <tal:block replace="structure request/indexargs_form" /> + </td> + </tr> + + .. code-tab:: html Jinja2 + + To Be Written which gives us a submit button, indicates that we are performing an edit on any changed statuses, and provides a defense against cross @@ -2189,6 +2301,8 @@ Changing How the Core Code Works -------------------------------- +.. index:: single: interfaces.py; cache-control headers + Changing Cache-Control Headers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2215,6 +2329,7 @@ Note that a file name match overrides the mime type settings. +.. index:: single: interfaces.py; password complexity checking Implement Password Complexity Checking ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2254,6 +2369,8 @@ version validates that the password is sufficiently complex. Then it passes off the setting of password to the original method. +.. index:: single: interfaces.py; interpreting time interval values + Enhance Time Intervals Forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2439,6 +2556,10 @@ <reference.html#extending-the-configuration-file>`_. * `Adding a new Permission <reference.html#adding-a-new-permission>`_ +as does the design document: + +* `detector examples <design.html#detector-example>`_ + Examples on the Wiki ==================== @@ -2446,11 +2567,13 @@ users. They can be found on the `wiki <https://wiki.roundup-tracker.org/CustomisationExamples>`_. +.. _change the rate limiting method: rest.html#creating-custom-rate-limits .. _`design documentation`: design.html .. _`developer's guide`: developers.html +.. _`directions in the rest interface documentation`: rest.html#enabling-the-rest-api +.. _oauth: https://wiki.roundup-tracker.org/OauthAuthentication .. _`rest interface documentation`: rest.html#programming-the-rest-api -.. _change the rate limiting method: rest.html#creating-custom-rate-limits -.. _`directions in the rest interface documentation`: rest.html#enabling-the-rest-api +.. _`shibboleth`: https://wiki.roundup-tracker.org/ShibbolethLogin .. _`xmlrpc interface documentation`: xmlrpc.html#through-roundup .. _`zxcvbn`: https://github.com/dwolfhub/zxcvbn-python
