3430 Commits

Author SHA1 Message Date
David Vadnais
bcb7c1796a Merge pull request #1386 from django-helpdesk/docs/cve-timing-caveat
docs: correct what happens if you publish before the CVE is assigned
2026-08-14 12:53:34 -10:00
David Vadnais
23272efaf0 Merge pull request #1382 from django-helpdesk/fix/followup-menu-empty
fix: hide the follow-up menu when it holds no actions
2026-08-14 12:52:46 -10:00
Christopher Broderick
4382f2f94e Merge branch 'main' into fix/followup-menu-empty 2026-08-14 23:36:20 +01:00
Benbb96
25a91ad40d docs: correct what happens if you publish before the CVE is assigned
Step 2 said publishing before the identifier arrives was fine because it gets
attached when GitHub's review completes. That turned out to be wrong, and we
found out the expensive way.

GitHub declined our request for GHSA-q46c-8w98-fq2g as a duplicate: VulnCheck
had already assigned CVE-2026-73531 five days after we published, deriving it
from our own advisory, which is listed as the first reference on the NVD record.
So the identifier exists, but with their severity (6.1) rather than ours (8.1),
and the wording is theirs too.

Publishing early is still often the right call, since step 5 wants the gap
between merge and an installable release measured in minutes. The point is that
it is a trade-off to make deliberately, not a step with no consequence.
2026-08-14 23:21:26 +02:00
David Vadnais
4eb58005a4 Merge pull request #1384 from gurupratap-matharu/enhancement/speed-up-test-suite
Enhancement/speed up test suite
2026-08-14 11:16:19 -10:00
Gurupratap Matharu
e338e802ef Use colorful buttons to upvote and downvote 2026-08-13 11:18:32 +05:30
Gurupratap Matharu
40b5da572c Remove Django settings environment variable while running tests 2026-08-13 11:02:56 +05:30
Gurupratap Matharu
8056328bdf Fix default argument in argparse to run all tests
Co-authored-by: David Vadnais <56882532+DavidVadnais@users.noreply.github.com>
2026-08-13 09:34:57 +05:30
Gurupratap Matharu
d5eabe8c08 Fix path syntax for DB settings
Co-authored-by: David Vadnais <56882532+DavidVadnais@users.noreply.github.com>
2026-08-13 09:34:17 +05:30
Christopher Broderick
1c00f93cb9 Merge pull request #1379 from DavidVadnais/feature/followup_list
feat: color code follow-ups by visibility and direction
2026-08-12 22:41:32 +01:00
David Vadnais
22e60079bb Merge branch 'main' into enhancement/speed-up-test-suite 2026-08-12 09:01:58 -10:00
David Vadnais
3bfd439ae2 Remove no longer installed bootstrap4form from test/test_settings.py 2026-08-12 08:59:31 -10:00
David Vadnais
60f3347d99 Merge branch 'main' into feature/followup_list 2026-08-12 08:35:08 -10:00
David Vadnais
3275d55d49 Merge pull request #1383 from django-helpdesk/fix/followup-edit-in-place
fix: edit follow-ups in place instead of recreating them
2026-08-12 08:32:34 -10:00
Gurupratap Matharu
9beb838662 Merge branch 'main' into enhancement/speed-up-test-suite 2026-08-12 13:31:39 +05:30
Gurupratap Matharu
c0d3ef66b9 Remove redundant class and simply test creation logic 2026-08-12 13:10:53 +05:30
Gurupratap Matharu
e77f6e5221 Move test settings out of quicktest for better separation of concerns 2026-08-12 13:09:59 +05:30
DavidVadnais
a9c40dcbb6 update docs to for followup colors, put examples in demo 2026-08-11 15:28:11 -10:00
Benbb96
e13864f40e fix: edit follow-ups in place instead of recreating them
Saving the edit form built a fresh FollowUp from the posted fields, moved
the attachments across and deleted the original. Everything the form does
not carry went with it: the message ID, so a reply received by e-mail
stopped being recognisable as one, and the TicketChange rows, which cascade
away with the row they point at, so a ticket lost the record of the status
and owner changes that follow-up carried. The new row also took a new
primary key, breaking any link to the follow-up.

Assign the posted fields to the existing follow-up and save it.
2026-08-12 00:47:08 +02:00
Benbb96
7d596b3953 fix: hide the follow-up menu when it holds no actions
The three dots menu on each follow-up rendered unconditionally, but both of
its entries are gated: Edit needs the follow-up to have an author and the
viewer to be that author or a superuser, and Delete needs a superuser plus
HELPDESK_SHOW_DELETE_BUTTON_SUPERUSER_FOLLOW_UP, which is off by default.
Staff therefore opened an empty menu on every follow-up written by a
colleague, and on every follow-up with no author at all: those received by
e-mail, those submitted from the public form and those raised by the
helpdesk itself.

Work out both permissions in template filters so the menu and its entries
cannot drift apart, and skip the menu when neither applies.
2026-08-12 00:39:04 +02:00
David Vadnais
23db802ac0 Merge branch 'main' into enhancement/improve-kb-list-detail-ui 2026-08-11 12:01:26 -10:00
David Vadnais
1513436ecd Merge pull request #1381 from DavidVadnais/docs/copyright-years
docs: auto pull in license to docs/license.rst

Both the documentation and the 3rd party.license file were falling out of date.

Now the documentation will auto pull in the data from the license file. We will still need to update the license file, especially as yarn and other tools accelerate our ability to update libraries
2026-08-11 08:22:23 -10:00
Gurupratap Matharu
250396f32d Adapt django message tags to bootstrap contextual classes 2026-08-11 15:49:24 +05:30
Gurupratap Matharu
1cd045295b Introduce a reusable messages template for the project 2026-08-11 15:48:42 +05:30
Gurupratap Matharu
e89141e141 Add success message once vote is registered 2026-08-11 15:48:00 +05:30
Christopher Broderick
b49586d88b Merge pull request #1378 from django-helpdesk/docs/security-private-reporting
docs: point reporters at private vulnerability reporting
2026-08-11 11:13:16 +01:00
Gurupratap Matharu
afee9fa82e Fix user to voter renaming in downvoting logic 2026-08-11 14:42:33 +05:30
Gurupratap Matharu
0a240ae8fd Open the accordion for the KB item absolute url
Instead of all accordion elements being closed we preopen the accordion element if its pk is part of the url; say for example /kb/orders/?kbitem=23 opens the respective accordion. This url is actually a detail url of a kb item
2026-08-11 14:04:10 +05:30
Gurupratap Matharu
515f955d50 Add page title tag as its no longer part of base-head template 2026-08-11 14:04:10 +05:30
Gurupratap Matharu
3476d127b6 Remove redundant Post method check and rename user -> voter 2026-08-11 14:03:29 +05:30
Gurupratap Matharu
3402643f42 Improve downvoting logic for a kb item
Co-authored-by: David Vadnais <56882532+DavidVadnais@users.noreply.github.com>
2026-08-11 12:45:52 +05:30
Gurupratap Matharu
da869c28b4 Add page title to knowledge base iframe template
Co-authored-by: David Vadnais <56882532+DavidVadnais@users.noreply.github.com>
2026-08-11 11:17:32 +05:30
Gurupratap Matharu
c6b3e5504f Show category description with line breaks applied as its text field
Co-authored-by: David Vadnais <56882532+DavidVadnais@users.noreply.github.com>
2026-08-11 11:13:13 +05:30
Gurupratap Matharu
a0d903565e Fix doc string typo error
Co-authored-by: David Vadnais <56882532+DavidVadnais@users.noreply.github.com>
2026-08-11 11:10:27 +05:30
Gurupratap Matharu
72ca0d8974 Render kb answers in markdown instead of plain text
Co-authored-by: David Vadnais <56882532+DavidVadnais@users.noreply.github.com>
2026-08-11 11:08:11 +05:30
DavidVadnais
252066be8e docs: correct third-party licenses from the installed packages
The 3rd party licenses had drifted from what we actually ship. Every
version label was stale and with the versions the attribution had gone stale too.
Three entries named the wrong copyright holder outright: jQuery still
credited John Resig personally rather than the OpenJS Foundation, Bootstrap
still credited Twitter, Inc., and Font Awesome carried no holder at all.

jQuery and jQuery UI become separate entries. They are separate packages at
separate versions, and their license texts genuinely differ -- jQuery UI's
adds a CC0 waiver for sample code -- so a single merged entry was always
wrong about one of them. The 'Smoothness' theme entry now states that it is
covered by the jQuery UI license

docs/license.rst then includes LICENSE.3RDPARTY rather than restating it,
the same treatment the BSD license got in the previous commit. That is what
caused this: the docs page was a hand-maintained third copy, and it had
drifted further than the file it copied. The per-library subsections
disappear from the page's table of contents, which is a real loss, but the
file carries its own index and a license page's first duty is to be
accurate.
2026-08-10 16:57:00 -10:00
DavidVadnais
5d91cf9f20 docs: auto pull in liscense to docs/license.rst 2026-08-10 16:16:14 -10:00
DavidVadnais
16f7dda2ea feat: color code follow-ups by visibility and direction
Closes #204.

A ticket's follow-up list mixes three kinds of entry: private staff notes,
replies sent out to the submitter, and messages received from the submitter,
and rendered all of them identically apart from a small 'Private' caption.
Staff scanning a long ticket had to read each entry to work out who could see
it, and the failure mode runs in the expensive direction: a note written as if
it were internal that the submitter can in fact read.
2026-08-10 15:00:16 -10:00
Benbb96
ad098c6f33 docs: point reporters at private vulnerability reporting
@uhurusurfa enabled private vulnerability reporting on the repository after
#1376, so the policy should send people there rather than to a personal email
address. The form opens a draft advisory only maintainers can see, with the
reporter already a collaborator on it, which is what step 1 of the handling
section asks us to set up by hand. The email address stays as a fallback for
anyone without a GitHub account.

Step 1 is reworded accordingly: a report that arrives through the form has
already created the draft, so there is nothing to open, only to take over.

Also settles the file on one sentence per line, agreed in #1376. The section
added there was hard wrapped near 80 columns while the older paragraphs each ran
as one long line. One sentence per line keeps lines short, touches exactly one
line in a diff when a sentence changes, and never needs rewrapping. Markdown
joins consecutive lines into a paragraph, so the rendered output is unchanged.
2026-08-10 23:46:04 +02:00
Christopher Broderick
542aa75019 Merge pull request #1377 from django-helpdesk/feat/bootstrap5-form-rendering
feat: render forms with our own Bootstrap 5 templates
2026-08-10 08:50:51 +01:00
Benbb96
2a39fea9b3 fix: style the submit button on the user settings form
The button was a bare <input type="submit"> carrying no class and no gettext
call, so it rendered as the browser default next to fields the rest of this
branch now renders with Bootstrap 5. It follows edit_ticket.html instead:
btn btn-primary btn-sm, with the label translated.
2026-08-10 01:01:31 +02:00
Benbb96
66ef7ca04b fix: keep the Bootstrap 5 widget family classes mutually exclusive
form-control, form-select and form-check-input set width differently, so a
widget carrying two of them renders wrong. apply_classes kept every class
already declared in forms.py, and forms.py declared form-control on both the
checkbox and the select it builds for custom fields. A boolean custom field
therefore reached the browser as "form-check-input form-control" and rendered
26px wide instead of 16px, a rectangle rather than a checkbox, on the edit
ticket form.

apply_classes now treats the three as one family and replaces rather than
accumulates, so a wrong class declared in a form cannot reach the markup.
Classes that have nothing to do with the family, such as date-field, are still
preserved.

forms.py is corrected at the source too: form-check-input on the boolean custom
field, form-select on the list one.

FormControlDeleteFormSet.deletion_widget still declares form-control on a
checkbox. It is rendered by the checklist templates rather than through
bootstrap5_form, so it is left for a separate change.
2026-08-10 01:01:31 +02:00
Benbb96
7812f1f10a feat: render forms with our own Bootstrap 5 templates
Closes #1375.

The UI ships Bootstrap 5.3.8, but form fields were rendered by
django-bootstrap4-form, whose markup is largely Bootstrap 3: form-group,
control-label, has-error, <div class="checkbox">. None of those classes exists
in the stylesheet we load, so the affected fields lost their bottom margin and
checkboxes and radios were unstyled.

The org's own django-bootstrap5-form was the obvious replacement but pins
django<4.0 while we require django>=4.2, so it cannot be installed alongside us.
Given the filter was used in exactly three templates, owning the rendering is
cheaper than maintaining a published package or adopting a larger one.

Adds a bootstrap5_form template tag and two templates. Widget classes are
assigned in Python rather than the template, because a widget rendered through
{{ field }} has already resolved its attributes: selects get form-select,
checkboxes and radios get form-check-input, everything else form-control, and
hidden inputs are left alone. Classes already declared in forms.py are kept,
including the ones that have nothing to do with Bootstrap.

Also removes four {% load bootstrap4form %} lines from templates that never
called the filter, and drops packaging, which was only declared because
django-bootstrap4-form imports it without declaring it.

Errors use `invalid-feedback d-block` rather than plain `invalid-feedback`: the
latter is only revealed by an adjacent `.is-invalid`, and that relationship does
not hold for radio groups and multiple checkboxes.
2026-08-10 00:07:47 +02:00
Christopher Broderick
e8358663ad Merge pull request #1376 from django-helpdesk/docs/security-advisory-process
docs: write down how we handle a security report
2026-08-09 22:47:40 +01:00
Benbb96
45d2206e53 docs: write down how we handle a security report
SECURITY.md covered how a reporter contacts us and stopped there. Everything
after that point was improvised, and the last two advisories showed the cost:
GHSA-mxcg-7m22-x9pj needed a second release because the first patch was
incomplete, and GHSA-q46c-8w98-fq2g was published a full day before 2.3.3
existed on PyPI, leaving the issue fully disclosed with no installable fix and
Dependabot pointing people at a version that did not exist.

Neither was any individual's mistake, which is the point: nobody owned the whole
chain. So the section starts by assigning an owner, then lists the seven steps
in the order that keeps the disclosure window short.
2026-08-09 23:40:08 +02:00
Christopher Broderick
bbe765895b Merge pull request #1374 from django-helpdesk/chore/optional-integrations
chore: make celery and akismet optional extras
Reduce number of extra packages installed.
2026-08-09 19:33:13 +01:00
Benbb96
1b4efe6269 chore: keep django-cleanup as a hard dependency
Per @uhurusurfa's review. Unlike celery and akismet, django-cleanup activates as
soon as it is listed in INSTALLED_APPS, which is exactly what our own
installation instructions tell people to do. Making it optional would stop a
documented configuration from starting at all, which is a different class of
breakage from the other two: `helpdesk/urls.py` already imports `helpdesk.tasks`
inside a try/except ImportError, and `text_is_spam()` already treats a missing
akismet as "not spam".

It also buys the least: django-cleanup pulls nothing else in, where celery alone
accounts for about twenty packages.

Docs and the upgrade note updated to match, and the upgrade note now says
explicitly why django-cleanup is not on the list, so this does not get proposed
again in six months.
2026-08-09 17:05:07 +02:00
Christopher Broderick
2036e2e817 Merge branch 'main' into enhancement/improve-kb-list-detail-ui 2026-08-09 10:06:24 +01:00
Gurupratap Matharu
9f92e1c861 Revert to older reverse url syntax 2026-08-09 11:01:16 +05:30
Gurupratap Matharu
be5a88012f Use older reverse url syntax as we test on django 4.2 in ci/cd 2026-08-09 11:00:09 +05:30