Skip to content

Celts User Profile, Wrong label for event participation type #1772

Description

@conwelld

Bug: Manually-created "All Volunteer Training" events are typed as Volunteer and display service hours on Participation History

Summary

Some events named "All Volunteer Training" were created through the generic Create Event form instead of the All Volunteer Training shortcut. Those events were saved without the training flag set, and with the service flag set instead.

Because of that, the Participation History table treats them as ordinary volunteer service events, gives them a participation type of Volunteer, and displays service hours next to them. Students who attended a training therefore appear to have earned service hours they should not have.

This is a data problem with a display symptom. The query and template logic are behaving as designed. They are being fed events whose flags describe them incorrectly.

Expected behavior

An "All Volunteer Training" event should be stored with:

Column Expected value
isAllVolunteerTraining 1
isService 0

Those events pass through the filter, get labeled Volunteer, and render service hours.

Steps to reproduce

1. Sign in to CELTS as an admin. You should land on the admin home page.

<Image

2. Go to the Student Search page. Search for Fritzj2 and click on Julius Fritz.

<Image

3. Click Participation History.

<Image

4. Find the row named All Volunteer Training. Its Participation Type reads Volunteer and its Service Hours column is populated, rather than the event being excluded from this table.

<Image <Image

Root cause

How the event got into this state

Events are added through Create Event.

<Image

There is an All Volunteer Training shortcut at the top of that form. Selecting it applies the correct flags automatically.

<Image

In several past cases the shortcut was not used. The event was instead created manually, typed in by name, and attached under an unrelated program. Nothing in the form requires the training flag to be set, so the record was saved as a regular service event that merely happens to be named "All Volunteer Training".

<Image

Why the wrong flags produce this specific output

For anyone new to this part of the codebase, two pieces of logic matter.

First, the filter. The Participation History query excludes training events with this condition in its where clause:

Event.isAllVolunteerTraining == False

An event with isAllVolunteerTraining = 0 is not excluded by that condition, so it stays in the result set.

Second, the label. Participation Type is not a stored column. It is computed in SQL by a Case expression in the select, which checks the event's flags in order and returns the first match:

Case(None, (
    ((Event.isLaborOnly | Event.name.contains("Labor")) & Event.isService, "Labor & Volunteer"),
    ((Event.isLaborOnly | Event.name.contains("Labor")), "Labor"),
    (Event.isService, "Volunteer")), "Attendee").alias("participatedType")

An event with isService = 1 falls into the third branch and is labeled Volunteer.

The template then shows hours only for rows whose type contains Volunteer:

{% if 'Volunteer' in event.participatedType %}
  <td>{{ ... hoursEarned ... }}</td>
{% else %}
  <td>N/A</td>
{% endif %}

So a single wrong flag at creation time cascades into a wrong label and a wrong hours display. Correctly-created training events have isService = 0, fall through to the "Attendee" default, and would show N/A even if the filter somehow missed them. That is the double protection the affected records are missing.

Evidence from the database

SELECT id, name, isAllVolunteerTraining, isService
FROM event
WHERE name LIKE '%All Volunteer%';

Most rows are correct:

|  id | name                            | isAllVolunteerTraining | isService |
|   2 | All Volunteer Training          |                      1 |         0 |
|  13 | All Volunteer Training          |                      1 |         0 |
|  98 | All Volunteer Training          |                      1 |         0 |
| ... |                                 |                        |           |

A subset is not:

| 703 | All Volunteer Training          |                      0 |         0 |
| 704 | All Volunteer Training          |                      0 |         0 |
| 706 | All Volunteer Training          |                      0 |         0 |

And at least one has the service flag set, which is the record surfacing in the screenshots above (event dated 09/04/2025). The full affected set can be listed with:

SELECT id, name, startDate, isAllVolunteerTraining, isService
FROM event
WHERE name LIKE '%All Volunteer%'
  AND isAllVolunteerTraining = 0;

Suggested fix

1. Identify the affected records. Run the query above and review each row by hand before changing anything. The name match is a substring search, so confirm each result really is an all-volunteer training and not a differently-scoped event that happens to share wording.

2. Correct the flags. For the confirmed rows:

UPDATE event
SET isAllVolunteerTraining = 1,
    isService = 0
WHERE id IN ( ... );

Both columns need updating. Setting only isAllVolunteerTraining removes the row from Participation History but leaves isService = 1, which means the event still counts toward service hour totals anywhere else in the application that aggregates on that flag.

3. Verify. Reload Julius Fritz's Participation History. The All Volunteer Training row should no longer appear.

Follow-up worth opening separately

This will recur. Nothing in the Create Event form prevents an admin from typing "All Volunteer Training" into a regular event, so the same cleanup will be needed again next time it happens.

Two possible directions, either of which deserves its own issue rather than being bundled here:

  • Validation or a warning on the Create Event form when the name matches an all-volunteer training but the shortcut was not used.
  • Reconsidering whether isAllVolunteerTraining and isService need to be maintained as two independent flags, given that they encode overlapping information and have already drifted apart on several records.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions