Skip to content

feat: display eligible member counts in admin pages#2578

Open
mroderick wants to merge 3 commits intocodebar:masterfrom
mroderick:feature/add-eligible-methods-to-chapter
Open

feat: display eligible member counts in admin pages#2578
mroderick wants to merge 3 commits intocodebar:masterfrom
mroderick:feature/add-eligible-methods-to-chapter

Conversation

@mroderick
Copy link
Copy Markdown
Collaborator

@mroderick mroderick commented Apr 16, 2026

Summary

This PR adds eligible member counts to admin pages, giving chapter organisers visibility into how many members can actually receive workshop invitations vs. total registered members.

Eligible members = members who have accepted Terms of Service AND are not banned/suspended.

Changes

Models

  • Chapter#eligible_students - Returns students eligible for invitations
  • Chapter#eligible_coaches - Returns coaches eligible for invitations
  • Group#eligible_members - Returns members eligible for invitations

Admin Views

  • Chapter show page: Shows "(X eligible, Y total)" for each group
  • Group show page: Shows "(X eligible, Y total)" in members header

Motivation

From investigation in #2576, Brighton chapter discovered that 43% of registered members (653 out of 1,513) weren't receiving invitations because they hadn't accepted the Terms of Service. These were primarily legacy members who registered before TOC was required in February 2020.

Currently, organisers only see total member counts, giving them no visibility into this gap. This PR addresses that by showing both numbers.

How to Verify

Step 1: Setup

git checkout feature/add-eligible-methods-to-chapter
bundle install
rails db:migrate  # if needed

Step 2: Run Tests

# Run model specs
bundle exec rspec spec/models/chapter_spec.rb spec/models/group_spec.rb

# Expected: 17 examples, 0 failures

# Run feature specs
bundle exec rspec spec/features/admin/

# Expected: All tests pass

Step 3: Manual Verification

  1. Start the Rails server:

    rails server
  2. Create test data (in rails console):

    chapter = Chapter.first || Chapter.create!(name: 'Test Chapter', city: 'Test City', email: 'test@example.com', time_zone: 'London')
    
    # Create student group
    students = Group.find_or_create_by!(chapter: chapter, name: 'Students')
    
    # Create eligible member (accepted TOC, not banned)
    eligible = Member.create!(
      name: 'Eligible', surname: 'Student', email: 'eligible@example.com',
      about_you: 'Test', accepted_toc_at: Time.now,
      auth_services: [AuthService.new(provider: 'github', uid: '12345')]
    )
    Subscription.create!(member: eligible, group: students)
    
    # Create ineligible member (no TOC)
    ineligible = Member.create!(
      name: 'Ineligible', surname: 'Student', email: 'ineligible@example.com',
      about_you: 'Test', accepted_toc_at: nil,
      auth_services: [AuthService.new(provider: 'github', uid: '67890')]
    )
    Subscription.create!(member: ineligible, group: students)
  3. Visit Admin Chapter Page:

  4. Visit Admin Group Page:

Step 4: Edge Cases (Optional)

  1. Create a banned member:

    banned = Member.create!(
      name: 'Banned', surname: 'Student', email: 'banned@example.com',
      about_you: 'Test', accepted_toc_at: Time.now,
      auth_services: [AuthService.new(provider: 'github', uid: '99999')]
    )
    Subscription.create!(member: banned, group: students)
    Ban.create!(
      member: banned,
      reason: 'Test ban',
      note: 'Test note',
      expires_at: 1.month.from_now,
      added_by: Member.first
    )
    • Refresh the pages
    • Expected: Eligible count stays at 1, total increases to 3
  2. Test with no eligible members:

    • Set all members' accepted_toc_at to nil
    • Expected: See "Students (0 eligible, N total)"

Alternative: Using Fabricators

If you have test data set up, you can use Fabricators instead:

chapter = Fabricate(:chapter)
students = Fabricate(:group, chapter: chapter, name: 'Students')

# Eligible member
Fabricate(:member, groups: [students], accepted_toc_at: Time.now)

# Ineligible member (no TOC)
Fabricate(:member_without_toc, groups: [students])

# Banned member
Fabricate(:banned_member, groups: [students], accepted_toc_at: Time.now)

Checklist

  • Added model methods with tests
  • Updated admin views
  • All tests pass
  • No RuboCop offenses (on new code)
  • Clean commit history

Related

Add methods to retrieve eligible students and coaches for a chapter.
Eligible members are those who:
- Have accepted the Terms of Service (accepted_toc_at is not nil)
- Are not banned (no active or permanent bans)

Uses the existing Member.in_group scope for consistency.
Add method to retrieve eligible members for a group.
Eligible members are those who:
- Have accepted the Terms of Service (accepted_toc_at is not nil)
- Are not banned (no active or permanent bans)

Uses members.not_banned.accepted_toc for clarity.
Update admin chapter and group pages to display both eligible member

counts (accepted TOC, not banned) and total member counts. This gives

organisers visibility into how many members can actually receive

workshop invitations.

- Chapter page: Shows eligible and total counts for each group

- Group page: Shows eligible and total counts in the members header
@mroderick
Copy link
Copy Markdown
Collaborator Author

From verifying this locally:

image image

@mroderick mroderick marked this pull request as ready for review April 16, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant